138032Speter/* 2261370Sgshapiro * 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 17266711SgshapiroSM_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 3590792Sgshapiro# 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; 52090792Sgshapiro#if _FFR_DAEMON_NETUNIX 52190792Sgshapiro# if NETUNIX 52290792Sgshapiro case AF_UNIX: 52390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 52490792Sgshapiro macid("{daemon_family}"), "local"); 52590792Sgshapiro break; 52690792Sgshapiro# endif /* NETUNIX */ 52790792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 52890792Sgshapiro#if NETINET 52964562Sgshapiro case AF_INET: 53090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53190792Sgshapiro macid("{daemon_family}"), "inet"); 53264562Sgshapiro break; 53390792Sgshapiro#endif /* NETINET */ 53490792Sgshapiro#if NETINET6 53564562Sgshapiro case AF_INET6: 53690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53790792Sgshapiro macid("{daemon_family}"), "inet6"); 53864562Sgshapiro break; 53990792Sgshapiro#endif /* NETINET6 */ 54090792Sgshapiro#if NETISO 54164562Sgshapiro case AF_ISO: 54290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54390792Sgshapiro macid("{daemon_family}"), "iso"); 54464562Sgshapiro break; 54590792Sgshapiro#endif /* NETISO */ 54690792Sgshapiro#if NETNS 54764562Sgshapiro case AF_NS: 54890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54990792Sgshapiro macid("{daemon_family}"), "ns"); 55064562Sgshapiro break; 55190792Sgshapiro#endif /* NETNS */ 55290792Sgshapiro#if NETX25 55364562Sgshapiro case AF_CCITT: 55490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55590792Sgshapiro macid("{daemon_family}"), "x.25"); 55664562Sgshapiro break; 55790792Sgshapiro#endif /* NETX25 */ 55864562Sgshapiro } 55990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56090792Sgshapiro macid("{daemon_name}"), 56190792Sgshapiro Daemons[curdaemon].d_name); 56264562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 56390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56490792Sgshapiro macid("{daemon_flags}"), 56590792Sgshapiro Daemons[curdaemon].d_mflags); 56664562Sgshapiro else 56790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56890792Sgshapiro macid("{daemon_flags}"), ""); 56964562Sgshapiro } 57064562Sgshapiro 57138032Speter /* 572132943Sgshapiro ** If connection rate is exceeded here, connection shall be 573132943Sgshapiro ** refused later by a new call after fork() by the 574132943Sgshapiro ** validate_connection() function. Closing the connection 575132943Sgshapiro ** at this point violates RFC 2821. 576132943Sgshapiro ** Do NOT remove this call, its side effects are needed. 577132943Sgshapiro */ 578132943Sgshapiro 579132943Sgshapiro connection_rate_check(&RealHostAddr, NULL); 580132943Sgshapiro 581132943Sgshapiro /* 58238032Speter ** Create a subprocess to process the mail. 58338032Speter */ 58438032Speter 58538032Speter if (tTd(15, 2)) 58690792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 58738032Speter 58838032Speter /* 58990792Sgshapiro ** Advance state of PRNG. 59090792Sgshapiro ** This is necessary because otherwise all child processes 59164562Sgshapiro ** will produce the same PRN sequence and hence the selection 59264562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 59364562Sgshapiro ** are not "really" random. 59464562Sgshapiro */ 59590792Sgshapiro#if STARTTLS 59690792Sgshapiro /* XXX get some better "random" data? */ 59766494Sgshapiro seed = get_random(); 59890792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 599168515Sgshapiro sizeof(NextDiskSpaceCheck)); 600168515Sgshapiro RAND_seed((void *) &now, sizeof(now)); 601168515Sgshapiro RAND_seed((void *) &seed, sizeof(seed)); 60290792Sgshapiro#else /* STARTTLS */ 60364562Sgshapiro (void) get_random(); 60490792Sgshapiro#endif /* STARTTLS */ 60564562Sgshapiro 60690792Sgshapiro#if NAMED_BIND 60764562Sgshapiro /* 608132943Sgshapiro ** Update MX records for FallbackMX. 60990792Sgshapiro ** Let's hope this is fast otherwise we screw up the 61090792Sgshapiro ** response time. 61190792Sgshapiro */ 61290792Sgshapiro 613132943Sgshapiro if (FallbackMX != NULL) 614132943Sgshapiro (void) getfallbackmxrr(FallbackMX); 61590792Sgshapiro#endif /* NAMED_BIND */ 61690792Sgshapiro 617110560Sgshapiro if (tTd(93, 100)) 618110560Sgshapiro { 619110560Sgshapiro /* don't fork, handle connection in this process */ 620110560Sgshapiro pid = 0; 62138032Speter pipefd[0] = pipefd[1] = -1; 622110560Sgshapiro } 623110560Sgshapiro else 624110560Sgshapiro { 625110560Sgshapiro /* 626110560Sgshapiro ** Create a pipe to keep the child from writing to 627110560Sgshapiro ** the socket until after the parent has closed 628110560Sgshapiro ** it. Otherwise the parent may hang if the child 629110560Sgshapiro ** has closed it first. 630110560Sgshapiro */ 63138032Speter 632110560Sgshapiro if (pipe(pipefd) < 0) 633110560Sgshapiro pipefd[0] = pipefd[1] = -1; 634110560Sgshapiro 635110560Sgshapiro (void) sm_blocksignal(SIGCHLD); 636110560Sgshapiro pid = fork(); 637110560Sgshapiro if (pid < 0) 63838032Speter { 639110560Sgshapiro syserr("daemon: cannot fork"); 640110560Sgshapiro if (pipefd[0] != -1) 641110560Sgshapiro { 642110560Sgshapiro (void) close(pipefd[0]); 643110560Sgshapiro (void) close(pipefd[1]); 644110560Sgshapiro } 645110560Sgshapiro (void) sm_releasesignal(SIGCHLD); 646110560Sgshapiro (void) sleep(10); 647110560Sgshapiro (void) close(t); 648110560Sgshapiro continue; 64938032Speter } 65038032Speter } 65190792Sgshapiro 65238032Speter if (pid == 0) 65338032Speter { 65438032Speter char *p; 65590792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 65638032Speter 65738032Speter /* 65838032Speter ** CHILD -- return to caller. 65938032Speter ** Collect verified idea of sending host. 66038032Speter ** Verify calling user id if possible here. 66138032Speter */ 66238032Speter 66377349Sgshapiro /* Reset global flags */ 66477349Sgshapiro RestartRequest = NULL; 66590792Sgshapiro RestartWorkGroup = false; 66677349Sgshapiro ShutdownRequest = NULL; 66777349Sgshapiro PendingSignal = 0; 66890792Sgshapiro CurrentPid = getpid(); 669132943Sgshapiro close_sendmail_pid(); 67077349Sgshapiro 67190792Sgshapiro (void) sm_releasesignal(SIGALRM); 67290792Sgshapiro (void) sm_releasesignal(SIGCHLD); 67390792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 67490792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 67590792Sgshapiro (void) sm_signal(SIGTERM, intsig); 67677349Sgshapiro 67790792Sgshapiro /* turn on profiling */ 67890792Sgshapiro /* SM_PROF(0); */ 67990792Sgshapiro 68090792Sgshapiro /* 68190792Sgshapiro ** Initialize exception stack and default exception 68290792Sgshapiro ** handler for child process. 68390792Sgshapiro */ 68490792Sgshapiro 68590792Sgshapiro sm_exc_newthread(fatal_error); 68690792Sgshapiro 68764562Sgshapiro if (!control) 68864562Sgshapiro { 68990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 69090792Sgshapiro macid("{daemon_addr}"), 69190792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 692168515Sgshapiro (void) sm_snprintf(status, sizeof(status), "%d", 69364562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 69490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 69590792Sgshapiro macid("{daemon_port}"), status); 69664562Sgshapiro } 69764562Sgshapiro 69890792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 69964562Sgshapiro { 70064562Sgshapiro if (Daemons[idx].d_socket >= 0) 70164562Sgshapiro (void) close(Daemons[idx].d_socket); 70280785Sgshapiro Daemons[idx].d_socket = -1; 70364562Sgshapiro } 70442575Speter clrcontrol(); 70538032Speter 70664562Sgshapiro /* Avoid SMTP daemon actions if control command */ 70764562Sgshapiro if (control) 70864562Sgshapiro { 70964562Sgshapiro /* Add control socket process */ 71090792Sgshapiro proc_list_add(CurrentPid, 71190792Sgshapiro "console socket child", 712132943Sgshapiro PROC_CONTROL_CHILD, 0, -1, NULL); 71364562Sgshapiro } 71464562Sgshapiro else 71564562Sgshapiro { 71664562Sgshapiro proc_list_clear(); 71742575Speter 71890792Sgshapiro /* clean up background delivery children */ 71990792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 72090792Sgshapiro 72164562Sgshapiro /* Add parent process as first child item */ 72290792Sgshapiro proc_list_add(CurrentPid, "daemon child", 723132943Sgshapiro PROC_DAEMON_CHILD, 0, -1, NULL); 72464562Sgshapiro /* don't schedule queue runs if ETRN */ 72564562Sgshapiro QueueIntvl = 0; 726168515Sgshapiro 727168515Sgshapiro /* 728168515Sgshapiro ** Hack: override global variables if 729168515Sgshapiro ** the corresponding DaemonPortOption 730168515Sgshapiro ** is set. 731168515Sgshapiro */ 732147078Sgshapiro#if _FFR_SS_PER_DAEMON 733147078Sgshapiro if (Daemons[curdaemon].d_supersafe != 734168515Sgshapiro DPO_NOTSET) 735168515Sgshapiro SuperSafe = Daemons[curdaemon]. 736168515Sgshapiro d_supersafe; 737147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 738147078Sgshapiro if (Daemons[curdaemon].d_dm != DM_NOTSET) 739147078Sgshapiro set_delivery_mode( 740147078Sgshapiro Daemons[curdaemon].d_dm, e); 74138032Speter 742168515Sgshapiro if (Daemons[curdaemon].d_refuseLA != 743168515Sgshapiro DPO_NOTSET) 744168515Sgshapiro RefuseLA = Daemons[curdaemon]. 745168515Sgshapiro d_refuseLA; 746168515Sgshapiro if (Daemons[curdaemon].d_queueLA != DPO_NOTSET) 747168515Sgshapiro QueueLA = Daemons[curdaemon].d_queueLA; 748168515Sgshapiro if (Daemons[curdaemon].d_delayLA != DPO_NOTSET) 749168515Sgshapiro DelayLA = Daemons[curdaemon].d_delayLA; 750168515Sgshapiro if (Daemons[curdaemon].d_maxchildren != 751168515Sgshapiro DPO_NOTSET) 752168515Sgshapiro MaxChildren = Daemons[curdaemon]. 753168515Sgshapiro d_maxchildren; 754168515Sgshapiro 75590792Sgshapiro sm_setproctitle(true, e, "startup with %s", 75664562Sgshapiro anynet_ntoa(&RealHostAddr)); 75764562Sgshapiro } 75864562Sgshapiro 75938032Speter if (pipefd[0] != -1) 76038032Speter { 76138032Speter auto char c; 76238032Speter 76338032Speter /* 76438032Speter ** Wait for the parent to close the write end 76538032Speter ** of the pipe, which we will see as an EOF. 76638032Speter ** This guarantees that we won't write to the 76738032Speter ** socket until after the parent has closed 76838032Speter ** the pipe. 76938032Speter */ 77038032Speter 77138032Speter /* close the write end of the pipe */ 77238032Speter (void) close(pipefd[1]); 77338032Speter 77438032Speter /* we shouldn't be interrupted, but ... */ 77538032Speter while (read(pipefd[0], &c, 1) < 0 && 77638032Speter errno == EINTR) 77738032Speter continue; 77838032Speter (void) close(pipefd[0]); 77938032Speter } 78038032Speter 78164562Sgshapiro /* control socket processing */ 78264562Sgshapiro if (control) 78364562Sgshapiro { 78464562Sgshapiro control_command(t, e); 78564562Sgshapiro /* NOTREACHED */ 78664562Sgshapiro exit(EX_SOFTWARE); 78764562Sgshapiro } 78864562Sgshapiro 78938032Speter /* determine host name */ 79038032Speter p = hostnamebyanyaddr(&RealHostAddr); 79190792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 79238032Speter p[MAXNAME] = '\0'; 79338032Speter RealHostName = newstr(p); 79464562Sgshapiro if (RealHostName[0] == '[') 79564562Sgshapiro { 79690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 79790792Sgshapiro macid("{client_resolve}"), 79890792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 79964562Sgshapiro } 80064562Sgshapiro else 801132943Sgshapiro { 80290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 803132943Sgshapiro macid("{client_resolve}"), "OK"); 804132943Sgshapiro } 80590792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 80694334Sgshapiro markstats(e, NULL, STATS_CONNECT); 80738032Speter 80890792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 80990792Sgshapiro SM_TIME_DEFAULT, 81090792Sgshapiro (void *) &t, 811132943Sgshapiro SM_IO_RDONLY_B, 81290792Sgshapiro NULL)) == NULL || 81338032Speter (t = dup(t)) < 0 || 81490792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 81590792Sgshapiro SM_TIME_DEFAULT, 81690792Sgshapiro (void *) &t, 817132943Sgshapiro SM_IO_WRONLY_B, 81890792Sgshapiro NULL)) == NULL) 81938032Speter { 82090792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 82190792Sgshapiro t); 82290792Sgshapiro finis(false, true, EX_OK); 82338032Speter } 82490792Sgshapiro sm_io_automode(inchannel, outchannel); 82538032Speter 82638032Speter InChannel = inchannel; 82738032Speter OutChannel = outchannel; 82890792Sgshapiro DisConnected = false; 82938032Speter 830244928Sgshapiro 83190792Sgshapiro#if XLA 83238032Speter if (!xla_host_ok(RealHostName)) 83338032Speter { 83464562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 83590792Sgshapiro finis(false, true, EX_OK); 83638032Speter } 83790792Sgshapiro#endif /* XLA */ 83864562Sgshapiro /* find out name for interface of connection */ 83990792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 84090792Sgshapiro NULL), &sa.sa, &len) == 0) 84164562Sgshapiro { 84264562Sgshapiro p = hostnamebyanyaddr(&sa); 84364562Sgshapiro if (tTd(15, 9)) 84490792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 84590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 84690792Sgshapiro macid("{if_name}"), p); 84764562Sgshapiro 84890792Sgshapiro /* 84990792Sgshapiro ** Do this only if it is not the loopback 85090792Sgshapiro ** interface. 85190792Sgshapiro */ 85290792Sgshapiro 85364562Sgshapiro if (!isloopback(sa)) 85464562Sgshapiro { 85590792Sgshapiro char *addr; 85690792Sgshapiro char family[5]; 85790792Sgshapiro 85890792Sgshapiro addr = anynet_ntoa(&sa); 85990792Sgshapiro (void) sm_snprintf(family, 86090792Sgshapiro sizeof(family), 86190792Sgshapiro "%d", sa.sa.sa_family); 86290792Sgshapiro macdefine(&BlankEnvelope.e_macro, 86390792Sgshapiro A_TEMP, 86490792Sgshapiro macid("{if_addr}"), addr); 86590792Sgshapiro macdefine(&BlankEnvelope.e_macro, 86690792Sgshapiro A_TEMP, 86790792Sgshapiro macid("{if_family}"), family); 86864562Sgshapiro if (tTd(15, 7)) 86990792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 87090792Sgshapiro addr, family); 87164562Sgshapiro } 87264562Sgshapiro else 87364562Sgshapiro { 87490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87590792Sgshapiro A_PERM, 87690792Sgshapiro macid("{if_addr}"), NULL); 87790792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87890792Sgshapiro A_PERM, 87990792Sgshapiro macid("{if_family}"), NULL); 88064562Sgshapiro } 88164562Sgshapiro } 88264562Sgshapiro else 88364562Sgshapiro { 88464562Sgshapiro if (tTd(15, 7)) 88590792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 88690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 88790792Sgshapiro macid("{if_name}"), NULL); 88890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 88990792Sgshapiro macid("{if_addr}"), NULL); 89090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 89190792Sgshapiro macid("{if_family}"), NULL); 89264562Sgshapiro } 89338032Speter break; 89438032Speter } 89538032Speter 89638032Speter /* parent -- keep track of children */ 89764562Sgshapiro if (control) 89864562Sgshapiro { 899168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 90090792Sgshapiro "control socket server child"); 901132943Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL); 90264562Sgshapiro } 90364562Sgshapiro else 90464562Sgshapiro { 905168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 90690792Sgshapiro "SMTP server child for %s", 90790792Sgshapiro anynet_ntoa(&RealHostAddr)); 908132943Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1, 909132943Sgshapiro &RealHostAddr); 91064562Sgshapiro } 91190792Sgshapiro (void) sm_releasesignal(SIGCHLD); 91238032Speter 91338032Speter /* close the read end of the synchronization pipe */ 91438032Speter if (pipefd[0] != -1) 91564562Sgshapiro { 91638032Speter (void) close(pipefd[0]); 91764562Sgshapiro pipefd[0] = -1; 91864562Sgshapiro } 91938032Speter 92038032Speter /* close the port so that others will hang (for a while) */ 92138032Speter (void) close(t); 92238032Speter 92338032Speter /* release the child by closing the read end of the sync pipe */ 92438032Speter if (pipefd[1] != -1) 92564562Sgshapiro { 92638032Speter (void) close(pipefd[1]); 92764562Sgshapiro pipefd[1] = -1; 92864562Sgshapiro } 92938032Speter } 93090792Sgshapiro if (tTd(15, 2)) 93190792Sgshapiro sm_dprintf("getreq: returning\n"); 93264562Sgshapiro 93390792Sgshapiro#if MILTER 93490792Sgshapiro /* set the filters for this daemon */ 93590792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 93690792Sgshapiro { 93790792Sgshapiro for (i = 0; 938110560Sgshapiro (i < MAXFILTERS && 939110560Sgshapiro Daemons[curdaemon].d_inputfilters[i] != NULL); 94090792Sgshapiro i++) 94190792Sgshapiro { 94290792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 94390792Sgshapiro } 94490792Sgshapiro if (i < MAXFILTERS) 94590792Sgshapiro InputFilters[i] = NULL; 94690792Sgshapiro } 94790792Sgshapiro#endif /* MILTER */ 94864562Sgshapiro return &Daemons[curdaemon].d_flags; 94938032Speter} 95090792Sgshapiro 95190792Sgshapiro/* 95290792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 95390792Sgshapiro** 95490792Sgshapiro** Parameters: 95590792Sgshapiro** e -- envelope. 95690792Sgshapiro** 95790792Sgshapiro** Returns: 95890792Sgshapiro** none. 95990792Sgshapiro** 96090792Sgshapiro** Side Effects: 96190792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 96290792Sgshapiro*/ 96390792Sgshapiro 96490792Sgshapirostatic void 96590792Sgshapirogetrequests_checkdiskspace(e) 96690792Sgshapiro ENVELOPE *e; 96790792Sgshapiro{ 96890792Sgshapiro bool logged = false; 96990792Sgshapiro int idx; 97090792Sgshapiro time_t now; 97190792Sgshapiro 97290792Sgshapiro now = curtime(); 97390792Sgshapiro if (now < NextDiskSpaceCheck) 97490792Sgshapiro return; 97590792Sgshapiro 97690792Sgshapiro /* Check if there is available disk space in all queue groups. */ 97790792Sgshapiro if (!enoughdiskspace(0, NULL)) 97890792Sgshapiro { 97990792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 98090792Sgshapiro { 98190792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 98290792Sgshapiro continue; 98390792Sgshapiro 98490792Sgshapiro /* log only if not logged before */ 98590792Sgshapiro if (!logged) 98690792Sgshapiro { 98790792Sgshapiro if (LogLevel > 8) 98890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 98990792Sgshapiro "rejecting new messages: min free: %ld", 99090792Sgshapiro MinBlocksFree); 99190792Sgshapiro sm_setproctitle(true, e, 99290792Sgshapiro "rejecting new messages: min free: %ld", 99390792Sgshapiro MinBlocksFree); 99490792Sgshapiro logged = true; 99590792Sgshapiro } 99690792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 99790792Sgshapiro } 99890792Sgshapiro } 99990792Sgshapiro else 100090792Sgshapiro { 100190792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 100290792Sgshapiro { 100390792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 100490792Sgshapiro continue; 100590792Sgshapiro 100690792Sgshapiro /* log only if not logged before */ 100790792Sgshapiro if (!logged) 100890792Sgshapiro { 100990792Sgshapiro if (LogLevel > 8) 101090792Sgshapiro sm_syslog(LOG_INFO, NOQID, 101190792Sgshapiro "accepting new messages (again)"); 101290792Sgshapiro logged = true; 101390792Sgshapiro } 101490792Sgshapiro 101590792Sgshapiro /* title will be set later */ 101690792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 101790792Sgshapiro } 101890792Sgshapiro } 101990792Sgshapiro 102090792Sgshapiro /* only check disk space once a minute */ 102190792Sgshapiro NextDiskSpaceCheck = now + 60; 102290792Sgshapiro} 102390792Sgshapiro 102490792Sgshapiro/* 102564562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 102638032Speter** 102764562Sgshapiro** Deals with setting all appropriate options. 102838032Speter** 102938032Speter** Parameters: 103064562Sgshapiro** d -- the structure for the daemon to open. 103138032Speter** firsttime -- set if this is the initial open. 103238032Speter** 103338032Speter** Returns: 103438032Speter** Size in bytes of the daemon socket addr. 103538032Speter** 103638032Speter** Side Effects: 103738032Speter** Leaves DaemonSocket set to the open socket. 103838032Speter** Exits if the socket cannot be created. 103938032Speter*/ 104038032Speter 104190792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 104238032Speter 104364562Sgshapirostatic int 104464562Sgshapiroopendaemonsocket(d, firsttime) 104590792Sgshapiro DAEMON_T *d; 104638032Speter bool firsttime; 104738032Speter{ 104838032Speter int on = 1; 104964562Sgshapiro int fdflags; 105064562Sgshapiro SOCKADDR_LEN_T socksize = 0; 105138032Speter int ntries = 0; 105264562Sgshapiro int save_errno; 105338032Speter 105438032Speter if (tTd(15, 2)) 105590792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 105638032Speter 105738032Speter do 105838032Speter { 105938032Speter if (ntries > 0) 106064562Sgshapiro (void) sleep(5); 106164562Sgshapiro if (firsttime || d->d_socket < 0) 106238032Speter { 106390792Sgshapiro#if _FFR_DAEMON_NETUNIX 106490792Sgshapiro# if NETUNIX 106590792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 106690792Sgshapiro { 106790792Sgshapiro int rval; 106890792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 106990792Sgshapiro 107090792Sgshapiro /* if not safe, don't use it */ 107190792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 107290792Sgshapiro RunAsUid, RunAsGid, 107390792Sgshapiro RunAsUserName, sff, 107490792Sgshapiro S_IRUSR|S_IWUSR, NULL); 107590792Sgshapiro if (rval != 0) 107690792Sgshapiro { 107790792Sgshapiro save_errno = errno; 107890792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 107990792Sgshapiro d->d_name, 108090792Sgshapiro d->d_addr.sunix.sun_path); 108190792Sgshapiro goto fail; 108290792Sgshapiro } 108390792Sgshapiro 108490792Sgshapiro /* Don't try to overtake an existing socket */ 108590792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 108690792Sgshapiro } 108790792Sgshapiro# endif /* NETUNIX */ 108890792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */ 108964562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 109064562Sgshapiro SOCK_STREAM, 0); 109164562Sgshapiro if (d->d_socket < 0) 109238032Speter { 109364562Sgshapiro save_errno = errno; 109490792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 109590792Sgshapiro d->d_name); 109690792Sgshapiro fail: 109790792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 109890792Sgshapiro (!transienterror(save_errno) || 109990792Sgshapiro ntries >= MAXOPENTRIES - 1)) 110090792Sgshapiro { 110190792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 110290792Sgshapiro d->d_name); 110390792Sgshapiro setbitn(D_DISABLE, d->d_flags); 110490792Sgshapiro d->d_socket = -1; 110590792Sgshapiro return -1; 110690792Sgshapiro } 110738032Speter severe: 110838032Speter if (LogLevel > 0) 110938032Speter sm_syslog(LOG_ALERT, NOQID, 111090792Sgshapiro "daemon %s: problem creating SMTP socket", 111190792Sgshapiro d->d_name); 111264562Sgshapiro d->d_socket = -1; 111338032Speter continue; 111438032Speter } 111538032Speter 1116110560Sgshapiro if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE) 1117110560Sgshapiro { 1118110560Sgshapiro save_errno = EINVAL; 1119110560Sgshapiro syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", 1120110560Sgshapiro d->d_name, d->d_socket); 1121110560Sgshapiro goto fail; 1122110560Sgshapiro } 1123110560Sgshapiro 112438032Speter /* turn on network debugging? */ 112538032Speter if (tTd(15, 101)) 112664562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 112738032Speter SO_DEBUG, (char *)&on, 1128168515Sgshapiro sizeof(on)); 112938032Speter 113064562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1131168515Sgshapiro SO_REUSEADDR, (char *)&on, sizeof(on)); 113264562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1133168515Sgshapiro SO_KEEPALIVE, (char *)&on, sizeof(on)); 113438032Speter 113590792Sgshapiro#ifdef SO_RCVBUF 113664562Sgshapiro if (d->d_tcprcvbufsize > 0) 113738032Speter { 113864562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 113938032Speter SO_RCVBUF, 114064562Sgshapiro (char *) &d->d_tcprcvbufsize, 114164562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 114264562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 114338032Speter } 114490792Sgshapiro#endif /* SO_RCVBUF */ 114590792Sgshapiro#ifdef SO_SNDBUF 114664562Sgshapiro if (d->d_tcpsndbufsize > 0) 114764562Sgshapiro { 114864562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 114964562Sgshapiro SO_SNDBUF, 115064562Sgshapiro (char *) &d->d_tcpsndbufsize, 115164562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 115264562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 115364562Sgshapiro } 115490792Sgshapiro#endif /* SO_SNDBUF */ 115538032Speter 115664562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 115764562Sgshapiro fcntl(d->d_socket, F_SETFD, 115864562Sgshapiro fdflags | FD_CLOEXEC) == -1) 115938032Speter { 116064562Sgshapiro save_errno = errno; 116164562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 116264562Sgshapiro d->d_name, 116364562Sgshapiro fdflags == -1 ? "get" : "set", 116490792Sgshapiro sm_errstring(save_errno)); 116564562Sgshapiro (void) close(d->d_socket); 116664562Sgshapiro goto severe; 116764562Sgshapiro } 116864562Sgshapiro 116964562Sgshapiro switch (d->d_addr.sa.sa_family) 117064562Sgshapiro { 117190792Sgshapiro#if _FFR_DAEMON_NETUNIX 117290792Sgshapiro# ifdef NETUNIX 117390792Sgshapiro case AF_UNIX: 1174168515Sgshapiro socksize = sizeof(d->d_addr.sunix); 117590792Sgshapiro break; 117690792Sgshapiro# endif /* NETUNIX */ 117790792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 117890792Sgshapiro#if NETINET 117938032Speter case AF_INET: 1180168515Sgshapiro socksize = sizeof(d->d_addr.sin); 118138032Speter break; 118290792Sgshapiro#endif /* NETINET */ 118338032Speter 118490792Sgshapiro#if NETINET6 118564562Sgshapiro case AF_INET6: 1186168515Sgshapiro socksize = sizeof(d->d_addr.sin6); 118764562Sgshapiro break; 118890792Sgshapiro#endif /* NETINET6 */ 118964562Sgshapiro 119090792Sgshapiro#if NETISO 119138032Speter case AF_ISO: 1192168515Sgshapiro socksize = sizeof(d->d_addr.siso); 119338032Speter break; 119490792Sgshapiro#endif /* NETISO */ 119538032Speter 119638032Speter default: 1197168515Sgshapiro socksize = sizeof(d->d_addr); 119838032Speter break; 119938032Speter } 120038032Speter 120164562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 120238032Speter { 120338032Speter /* probably another daemon already */ 120464562Sgshapiro save_errno = errno; 120564562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 120664562Sgshapiro d->d_name); 120764562Sgshapiro (void) close(d->d_socket); 120890792Sgshapiro goto fail; 120938032Speter } 121038032Speter } 121164562Sgshapiro if (!firsttime && 121264562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 121338032Speter { 121464562Sgshapiro save_errno = errno; 121564562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 121664562Sgshapiro d->d_name); 121764562Sgshapiro (void) close(d->d_socket); 121838032Speter goto severe; 121938032Speter } 122038032Speter return socksize; 122164562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 122264562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 122364562Sgshapiro d->d_name); 122464562Sgshapiro /* NOTREACHED */ 122538032Speter return -1; /* avoid compiler warning on IRIX */ 122638032Speter} 122790792Sgshapiro/* 122864562Sgshapiro** SETUPDAEMON -- setup socket for daemon 122964562Sgshapiro** 123064562Sgshapiro** Parameters: 123164562Sgshapiro** daemonaddr -- socket for daemon 123264562Sgshapiro** 123364562Sgshapiro** Returns: 123464562Sgshapiro** port number on which daemon should run 123564562Sgshapiro** 123664562Sgshapiro*/ 123790792Sgshapiro 123890792Sgshapirostatic unsigned short 123964562Sgshapirosetupdaemon(daemonaddr) 124064562Sgshapiro SOCKADDR *daemonaddr; 124164562Sgshapiro{ 124290792Sgshapiro unsigned short port; 124364562Sgshapiro 124464562Sgshapiro /* 124564562Sgshapiro ** Set up the address for the mailer. 124664562Sgshapiro */ 124764562Sgshapiro 124864562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 124964562Sgshapiro { 1250168515Sgshapiro memset(daemonaddr, '\0', sizeof(*daemonaddr)); 125190792Sgshapiro#if NETINET 125264562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 125390792Sgshapiro#endif /* NETINET */ 125464562Sgshapiro } 125564562Sgshapiro 125664562Sgshapiro switch (daemonaddr->sa.sa_family) 125764562Sgshapiro { 125890792Sgshapiro#if NETINET 125964562Sgshapiro case AF_INET: 126064562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 1261182352Sgshapiro daemonaddr->sin.sin_addr.s_addr = 1262182352Sgshapiro LocalDaemon ? htonl(INADDR_LOOPBACK) : INADDR_ANY; 126364562Sgshapiro port = daemonaddr->sin.sin_port; 126464562Sgshapiro break; 126590792Sgshapiro#endif /* NETINET */ 126664562Sgshapiro 126790792Sgshapiro#if NETINET6 126864562Sgshapiro case AF_INET6: 126964562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 1270182352Sgshapiro daemonaddr->sin6.sin6_addr = 1271223067Sgshapiro (LocalDaemon && V6LoopbackAddrFound) ? 1272223067Sgshapiro in6addr_loopback : in6addr_any; 127364562Sgshapiro port = daemonaddr->sin6.sin6_port; 127464562Sgshapiro break; 127590792Sgshapiro#endif /* NETINET6 */ 127664562Sgshapiro 127764562Sgshapiro default: 127864562Sgshapiro /* unknown protocol */ 127964562Sgshapiro port = 0; 128064562Sgshapiro break; 128164562Sgshapiro } 128264562Sgshapiro if (port == 0) 128364562Sgshapiro { 128490792Sgshapiro#ifdef NO_GETSERVBYNAME 128564562Sgshapiro port = htons(25); 128690792Sgshapiro#else /* NO_GETSERVBYNAME */ 128764562Sgshapiro { 128864562Sgshapiro register struct servent *sp; 128964562Sgshapiro 129064562Sgshapiro sp = getservbyname("smtp", "tcp"); 129164562Sgshapiro if (sp == NULL) 129264562Sgshapiro { 129364562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 129464562Sgshapiro port = htons(25); 129564562Sgshapiro } 129664562Sgshapiro else 129764562Sgshapiro port = sp->s_port; 129864562Sgshapiro } 129990792Sgshapiro#endif /* NO_GETSERVBYNAME */ 130064562Sgshapiro } 130164562Sgshapiro 130264562Sgshapiro switch (daemonaddr->sa.sa_family) 130364562Sgshapiro { 130490792Sgshapiro#if NETINET 130564562Sgshapiro case AF_INET: 130664562Sgshapiro daemonaddr->sin.sin_port = port; 130764562Sgshapiro break; 130890792Sgshapiro#endif /* NETINET */ 130964562Sgshapiro 131090792Sgshapiro#if NETINET6 131164562Sgshapiro case AF_INET6: 131264562Sgshapiro daemonaddr->sin6.sin6_port = port; 131364562Sgshapiro break; 131490792Sgshapiro#endif /* NETINET6 */ 131564562Sgshapiro 131664562Sgshapiro default: 131764562Sgshapiro /* unknown protocol */ 131864562Sgshapiro break; 131964562Sgshapiro } 132090792Sgshapiro return port; 132164562Sgshapiro} 132290792Sgshapiro/* 132338032Speter** CLRDAEMON -- reset the daemon connection 132438032Speter** 132538032Speter** Parameters: 132638032Speter** none. 132738032Speter** 132838032Speter** Returns: 132938032Speter** none. 133038032Speter** 133138032Speter** Side Effects: 133238032Speter** releases any resources used by the passive daemon. 133338032Speter*/ 133438032Speter 133538032Spetervoid 133638032Speterclrdaemon() 133738032Speter{ 133864562Sgshapiro int i; 133964562Sgshapiro 134090792Sgshapiro for (i = 0; i < NDaemons; i++) 134164562Sgshapiro { 134264562Sgshapiro if (Daemons[i].d_socket >= 0) 134364562Sgshapiro (void) close(Daemons[i].d_socket); 134464562Sgshapiro Daemons[i].d_socket = -1; 134564562Sgshapiro } 134638032Speter} 134790792Sgshapiro 134890792Sgshapiro/* 134990792Sgshapiro** GETMODIFIERS -- get modifier flags 135090792Sgshapiro** 135190792Sgshapiro** Parameters: 135290792Sgshapiro** v -- the modifiers (input text line). 135390792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 135490792Sgshapiro** 135590792Sgshapiro** Returns: 135690792Sgshapiro** (xallocat()ed) string representation of modifiers. 135790792Sgshapiro** 135890792Sgshapiro** Side Effects: 135990792Sgshapiro** fills in modifiers. 136090792Sgshapiro*/ 136190792Sgshapiro 136290792Sgshapirochar * 136390792Sgshapirogetmodifiers(v, modifiers) 136490792Sgshapiro char *v; 136590792Sgshapiro BITMAP256 modifiers; 136690792Sgshapiro{ 136790792Sgshapiro int l; 136890792Sgshapiro char *h, *f, *flags; 136990792Sgshapiro 137090792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 137190792Sgshapiro l = 3 * strlen(v) + 3; 137290792Sgshapiro 137390792Sgshapiro /* is someone joking? */ 137490792Sgshapiro if (l < 0 || l > 256) 137590792Sgshapiro { 137690792Sgshapiro if (LogLevel > 2) 137790792Sgshapiro sm_syslog(LOG_ERR, NOQID, 137890792Sgshapiro "getmodifiers too long, ignored"); 137990792Sgshapiro return NULL; 138090792Sgshapiro } 138190792Sgshapiro flags = xalloc(l); 138290792Sgshapiro f = flags; 138390792Sgshapiro clrbitmap(modifiers); 138490792Sgshapiro for (h = v; *h != '\0'; h++) 138590792Sgshapiro { 138690792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 138790792Sgshapiro { 138890792Sgshapiro setbitn(*h, modifiers); 138990792Sgshapiro if (flags != f) 139090792Sgshapiro *flags++ = ' '; 139190792Sgshapiro *flags++ = *h; 139290792Sgshapiro if (isupper(*h)) 139390792Sgshapiro *flags++ = *h; 139490792Sgshapiro } 139590792Sgshapiro } 139690792Sgshapiro *flags++ = '\0'; 139790792Sgshapiro return f; 139890792Sgshapiro} 139990792Sgshapiro 140090792Sgshapiro/* 140190792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 140290792Sgshapiro** 140390792Sgshapiro** Parameters: 140490792Sgshapiro** flag -- the flag to test. 140590792Sgshapiro** 140690792Sgshapiro** Returns: 140790792Sgshapiro** true iff all daemons have set flag. 140890792Sgshapiro*/ 140990792Sgshapiro 141090792Sgshapirobool 141190792Sgshapirochkdaemonmodifiers(flag) 141290792Sgshapiro int flag; 141390792Sgshapiro{ 141490792Sgshapiro int i; 141590792Sgshapiro 141690792Sgshapiro for (i = 0; i < NDaemons; i++) 141790792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 141890792Sgshapiro return false; 141990792Sgshapiro return true; 142090792Sgshapiro} 142190792Sgshapiro 142290792Sgshapiro/* 142364562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 142438032Speter** 142538032Speter** Parameters: 142638032Speter** p -- the options line. 142764562Sgshapiro** d -- the daemon structure to fill in. 142838032Speter** 142938032Speter** Returns: 143038032Speter** none. 143138032Speter*/ 143238032Speter 143364562Sgshapirostatic void 143464562Sgshapirosetsockaddroptions(p, d) 1435141858Sgshapiro char *p; 143690792Sgshapiro DAEMON_T *d; 143738032Speter{ 143890792Sgshapiro#if NETISO 143971345Sgshapiro short portno; 144090792Sgshapiro#endif /* NETISO */ 144171345Sgshapiro char *port = NULL; 144271345Sgshapiro char *addr = NULL; 144338032Speter 144490792Sgshapiro#if NETINET 144564562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 144664562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 144790792Sgshapiro#endif /* NETINET */ 1448157001Sgshapiro#if _FFR_SS_PER_DAEMON 1449168515Sgshapiro d->d_supersafe = DPO_NOTSET; 1450157001Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1451157001Sgshapiro d->d_dm = DM_NOTSET; 1452168515Sgshapiro d->d_refuseLA = DPO_NOTSET; 1453168515Sgshapiro d->d_queueLA = DPO_NOTSET; 1454168515Sgshapiro d->d_delayLA = DPO_NOTSET; 1455168515Sgshapiro d->d_maxchildren = DPO_NOTSET; 145664562Sgshapiro 145738032Speter while (p != NULL) 145838032Speter { 145938032Speter register char *f; 146038032Speter register char *v; 146138032Speter 146238032Speter while (isascii(*p) && isspace(*p)) 146338032Speter p++; 146438032Speter if (*p == '\0') 146538032Speter break; 146638032Speter f = p; 146738032Speter p = strchr(p, ','); 146838032Speter if (p != NULL) 146938032Speter *p++ = '\0'; 147038032Speter v = strchr(f, '='); 147138032Speter if (v == NULL) 147238032Speter continue; 147338032Speter while (isascii(*++v) && isspace(*v)) 147438032Speter continue; 147538032Speter 147638032Speter switch (*f) 147738032Speter { 1478147078Sgshapiro case 'A': /* address */ 1479168515Sgshapiro#if !_FFR_DPO_CS 1480168515Sgshapiro case 'a': 1481168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1482147078Sgshapiro addr = v; 1483147078Sgshapiro break; 1484147078Sgshapiro 1485168515Sgshapiro case 'c': 1486168515Sgshapiro d->d_maxchildren = atoi(v); 1487168515Sgshapiro break; 1488168515Sgshapiro 1489147078Sgshapiro case 'D': /* DeliveryMode */ 1490147078Sgshapiro switch (*v) 1491147078Sgshapiro { 1492147078Sgshapiro case SM_QUEUE: 1493147078Sgshapiro case SM_DEFER: 1494147078Sgshapiro case SM_DELIVER: 1495157001Sgshapiro case SM_FORK: 1496147078Sgshapiro d->d_dm = *v; 1497147078Sgshapiro break; 1498147078Sgshapiro default: 1499147078Sgshapiro syserr("554 5.3.5 Unknown delivery mode %c", 1500147078Sgshapiro *v); 1501147078Sgshapiro break; 1502147078Sgshapiro } 1503147078Sgshapiro break; 1504147078Sgshapiro 1505168515Sgshapiro case 'd': /* delayLA */ 1506168515Sgshapiro d->d_delayLA = atoi(v); 1507168515Sgshapiro break; 1508168515Sgshapiro 150938032Speter case 'F': /* address family */ 1510168515Sgshapiro#if !_FFR_DPO_CS 1511168515Sgshapiro case 'f': 1512168515Sgshapiro#endif /* !_FFR_DPO_CS */ 151338032Speter if (isascii(*v) && isdigit(*v)) 151464562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 151590792Sgshapiro#if _FFR_DAEMON_NETUNIX 151690792Sgshapiro# ifdef NETUNIX 151790792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 151890792Sgshapiro sm_strcasecmp(v, "local") == 0) 151990792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 152090792Sgshapiro# endif /* NETUNIX */ 152190792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 152290792Sgshapiro#if NETINET 152390792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 152464562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 152590792Sgshapiro#endif /* NETINET */ 152690792Sgshapiro#if NETINET6 152790792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 152864562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 152990792Sgshapiro#endif /* NETINET6 */ 153090792Sgshapiro#if NETISO 153190792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 153264562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 153390792Sgshapiro#endif /* NETISO */ 153490792Sgshapiro#if NETNS 153590792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 153664562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 153790792Sgshapiro#endif /* NETNS */ 153890792Sgshapiro#if NETX25 153990792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 154064562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 154190792Sgshapiro#endif /* NETX25 */ 154238032Speter else 154364562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 154464562Sgshapiro v); 154538032Speter break; 154638032Speter 154790792Sgshapiro#if MILTER 154890792Sgshapiro case 'I': 1549168515Sgshapiro# if !_FFR_DPO_CS 1550168515Sgshapiro case 'i': 1551168515Sgshapiro# endif /* !_FFR_DPO_CS */ 155290792Sgshapiro d->d_inputfilterlist = v; 155390792Sgshapiro break; 155490792Sgshapiro#endif /* MILTER */ 155590792Sgshapiro 155638032Speter case 'L': /* listen queue size */ 1557168515Sgshapiro#if !_FFR_DPO_CS 1558168515Sgshapiro case 'l': 1559168515Sgshapiro#endif /* !_FFR_DPO_CS */ 156064562Sgshapiro d->d_listenqueue = atoi(v); 156138032Speter break; 156238032Speter 156364562Sgshapiro case 'M': /* modifiers (flags) */ 1564168515Sgshapiro#if !_FFR_DPO_CS 1565168515Sgshapiro case 'm': 1566168515Sgshapiro#endif /* !_FFR_DPO_CS */ 156790792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 156864562Sgshapiro break; 156964562Sgshapiro 1570147078Sgshapiro case 'N': /* name */ 1571168515Sgshapiro#if !_FFR_DPO_CS 1572168515Sgshapiro case 'n': 1573168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1574147078Sgshapiro d->d_name = v; 157538032Speter break; 157638032Speter 1577147078Sgshapiro case 'P': /* port */ 1578168515Sgshapiro#if !_FFR_DPO_CS 1579168515Sgshapiro case 'p': 1580168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1581147078Sgshapiro port = v; 1582147078Sgshapiro break; 1583147078Sgshapiro 1584168515Sgshapiro case 'q': 1585168515Sgshapiro d->d_queueLA = atoi(v); 1586168515Sgshapiro break; 1587168515Sgshapiro 158838032Speter case 'R': /* receive buffer size */ 158964562Sgshapiro d->d_tcprcvbufsize = atoi(v); 159038032Speter break; 159138032Speter 1592168515Sgshapiro case 'r': 1593168515Sgshapiro d->d_refuseLA = atoi(v); 1594168515Sgshapiro break; 1595168515Sgshapiro 1596147078Sgshapiro case 'S': /* send buffer size */ 1597168515Sgshapiro#if !_FFR_DPO_CS 1598168515Sgshapiro case 's': 1599168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1600147078Sgshapiro d->d_tcpsndbufsize = atoi(v); 160164562Sgshapiro break; 160264562Sgshapiro 1603147078Sgshapiro#if _FFR_SS_PER_DAEMON 1604147078Sgshapiro case 'T': /* SuperSafe */ 1605147078Sgshapiro if (tolower(*v) == 'i') 1606147078Sgshapiro d->d_supersafe = SAFE_INTERACTIVE; 1607147078Sgshapiro else if (tolower(*v) == 'p') 1608147078Sgshapiro# if MILTER 1609147078Sgshapiro d->d_supersafe = SAFE_REALLY_POSTMILTER; 1610147078Sgshapiro# else /* MILTER */ 1611147078Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1612147078Sgshapiro "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 1613147078Sgshapiro# endif /* MILTER */ 1614147078Sgshapiro else 1615147078Sgshapiro d->d_supersafe = atobool(v) ? SAFE_REALLY 1616147078Sgshapiro : SAFE_NO; 1617147078Sgshapiro break; 1618147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1619147078Sgshapiro 162038032Speter default: 162164562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 162264562Sgshapiro f); 162338032Speter } 162438032Speter } 162571345Sgshapiro 162671345Sgshapiro /* Check addr and port after finding family */ 162771345Sgshapiro if (addr != NULL) 162871345Sgshapiro { 162971345Sgshapiro switch (d->d_addr.sa.sa_family) 163071345Sgshapiro { 163190792Sgshapiro#if _FFR_DAEMON_NETUNIX 163290792Sgshapiro# if NETUNIX 163390792Sgshapiro case AF_UNIX: 163490792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 163590792Sgshapiro { 163690792Sgshapiro errno = ENAMETOOLONG; 163790792Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %d", 163890792Sgshapiro addr, sizeof(d->d_addr.sunix.sun_path)); 163990792Sgshapiro break; 164090792Sgshapiro } 164190792Sgshapiro 164290792Sgshapiro /* file safety check done in opendaemonsocket() */ 164390792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 164490792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 164590792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 164690792Sgshapiro addr, 164790792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 164890792Sgshapiro break; 164990792Sgshapiro# endif /* NETUNIX */ 165090792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 165190792Sgshapiro#if NETINET 165271345Sgshapiro case AF_INET: 165371345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 165490792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 165590792Sgshapiro == INADDR_NONE)) 165671345Sgshapiro { 165771345Sgshapiro register struct hostent *hp; 165871345Sgshapiro 165971345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 166071345Sgshapiro if (hp == NULL) 166171345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 166271345Sgshapiro addr); 166371345Sgshapiro else 166471345Sgshapiro { 166571345Sgshapiro while (*(hp->h_addr_list) != NULL && 166671345Sgshapiro hp->h_addrtype != AF_INET) 166771345Sgshapiro hp->h_addr_list++; 166871345Sgshapiro if (*(hp->h_addr_list) == NULL) 166971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 167071345Sgshapiro addr); 167171345Sgshapiro else 167271345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 167371345Sgshapiro *(hp->h_addr_list), 167471345Sgshapiro INADDRSZ); 167590792Sgshapiro# if NETINET6 167671345Sgshapiro freehostent(hp); 167771345Sgshapiro hp = NULL; 167890792Sgshapiro# endif /* NETINET6 */ 167971345Sgshapiro } 168071345Sgshapiro } 168171345Sgshapiro break; 168290792Sgshapiro#endif /* NETINET */ 168371345Sgshapiro 168490792Sgshapiro#if NETINET6 168571345Sgshapiro case AF_INET6: 168690792Sgshapiro if (anynet_pton(AF_INET6, addr, 168790792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 168871345Sgshapiro { 168971345Sgshapiro register struct hostent *hp; 169071345Sgshapiro 169171345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 169271345Sgshapiro if (hp == NULL) 169371345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 169471345Sgshapiro addr); 169571345Sgshapiro else 169671345Sgshapiro { 169771345Sgshapiro while (*(hp->h_addr_list) != NULL && 169871345Sgshapiro hp->h_addrtype != AF_INET6) 169971345Sgshapiro hp->h_addr_list++; 170071345Sgshapiro if (*(hp->h_addr_list) == NULL) 170171345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 170271345Sgshapiro addr); 170371345Sgshapiro else 170471345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 170571345Sgshapiro *(hp->h_addr_list), 170671345Sgshapiro IN6ADDRSZ); 170771345Sgshapiro freehostent(hp); 170871345Sgshapiro hp = NULL; 170971345Sgshapiro } 171071345Sgshapiro } 171171345Sgshapiro break; 171290792Sgshapiro#endif /* NETINET6 */ 171371345Sgshapiro 171471345Sgshapiro default: 171571345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 171671345Sgshapiro d->d_addr.sa.sa_family); 171771345Sgshapiro break; 171871345Sgshapiro } 171971345Sgshapiro } 172071345Sgshapiro 172171345Sgshapiro if (port != NULL) 172271345Sgshapiro { 172371345Sgshapiro switch (d->d_addr.sa.sa_family) 172471345Sgshapiro { 172590792Sgshapiro#if NETINET 172671345Sgshapiro case AF_INET: 172771345Sgshapiro if (isascii(*port) && isdigit(*port)) 172890792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 172990792Sgshapiro atoi((const char *) port)); 173071345Sgshapiro else 173171345Sgshapiro { 173290792Sgshapiro# ifdef NO_GETSERVBYNAME 173371345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 173471345Sgshapiro port); 173590792Sgshapiro# else /* NO_GETSERVBYNAME */ 173671345Sgshapiro register struct servent *sp; 173771345Sgshapiro 173871345Sgshapiro sp = getservbyname(port, "tcp"); 173971345Sgshapiro if (sp == NULL) 174071345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 174171345Sgshapiro port); 174271345Sgshapiro else 174371345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 174490792Sgshapiro# endif /* NO_GETSERVBYNAME */ 174571345Sgshapiro } 174671345Sgshapiro break; 174790792Sgshapiro#endif /* NETINET */ 174871345Sgshapiro 174990792Sgshapiro#if NETINET6 175071345Sgshapiro case AF_INET6: 175171345Sgshapiro if (isascii(*port) && isdigit(*port)) 175290792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 175390792Sgshapiro atoi(port)); 175471345Sgshapiro else 175571345Sgshapiro { 175690792Sgshapiro# ifdef NO_GETSERVBYNAME 175771345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 175871345Sgshapiro port); 175990792Sgshapiro# else /* NO_GETSERVBYNAME */ 176071345Sgshapiro register struct servent *sp; 176171345Sgshapiro 176271345Sgshapiro sp = getservbyname(port, "tcp"); 176371345Sgshapiro if (sp == NULL) 176471345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 176571345Sgshapiro port); 176671345Sgshapiro else 176771345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 176890792Sgshapiro# endif /* NO_GETSERVBYNAME */ 176971345Sgshapiro } 177071345Sgshapiro break; 177190792Sgshapiro#endif /* NETINET6 */ 177271345Sgshapiro 177390792Sgshapiro#if NETISO 177471345Sgshapiro case AF_ISO: 177571345Sgshapiro /* assume two byte transport selector */ 177671345Sgshapiro if (isascii(*port) && isdigit(*port)) 177790792Sgshapiro portno = htons((unsigned short) atoi(port)); 177871345Sgshapiro else 177971345Sgshapiro { 178090792Sgshapiro# ifdef NO_GETSERVBYNAME 178171345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 178271345Sgshapiro port); 178390792Sgshapiro# else /* NO_GETSERVBYNAME */ 178471345Sgshapiro register struct servent *sp; 178571345Sgshapiro 178671345Sgshapiro sp = getservbyname(port, "tcp"); 178771345Sgshapiro if (sp == NULL) 178871345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 178971345Sgshapiro port); 179071345Sgshapiro else 179171345Sgshapiro portno = sp->s_port; 179290792Sgshapiro# endif /* NO_GETSERVBYNAME */ 179371345Sgshapiro } 179471345Sgshapiro memmove(TSEL(&d->d_addr.siso), 179571345Sgshapiro (char *) &portno, 2); 179671345Sgshapiro break; 179790792Sgshapiro#endif /* NETISO */ 179871345Sgshapiro 179971345Sgshapiro default: 180071345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 180171345Sgshapiro d->d_addr.sa.sa_family); 180271345Sgshapiro break; 180371345Sgshapiro } 180471345Sgshapiro } 180538032Speter} 180690792Sgshapiro/* 180764562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 180838032Speter** 180938032Speter** Parameters: 181064562Sgshapiro** p -- the options line. 181164562Sgshapiro** 181264562Sgshapiro** Returns: 181390792Sgshapiro** true if successful, false otherwise. 181490792Sgshapiro** 181590792Sgshapiro** Side Effects: 181690792Sgshapiro** increments number of daemons. 181764562Sgshapiro*/ 181864562Sgshapiro 181990792Sgshapiro#define DEF_LISTENQUEUE 10 182090792Sgshapiro 182198841Sgshapirostruct dflags 182298841Sgshapiro{ 182398841Sgshapiro char *d_name; 182498841Sgshapiro int d_flag; 182598841Sgshapiro}; 182698841Sgshapiro 182798841Sgshapirostatic struct dflags DaemonFlags[] = 182898841Sgshapiro{ 182998841Sgshapiro { "AUTHREQ", D_AUTHREQ }, 183098841Sgshapiro { "BINDIF", D_BINDIF }, 183198841Sgshapiro { "CANONREQ", D_CANONREQ }, 183298841Sgshapiro { "IFNHELO", D_IFNHELO }, 183398841Sgshapiro { "FQMAIL", D_FQMAIL }, 183498841Sgshapiro { "FQRCPT", D_FQRCPT }, 183598841Sgshapiro { "SMTPS", D_SMTPS }, 183698841Sgshapiro { "UNQUALOK", D_UNQUALOK }, 183798841Sgshapiro { "NOAUTH", D_NOAUTH }, 183898841Sgshapiro { "NOCANON", D_NOCANON }, 183998841Sgshapiro { "NOETRN", D_NOETRN }, 184098841Sgshapiro { "NOTLS", D_NOTLS }, 184198841Sgshapiro { "ETRNONLY", D_ETRNONLY }, 184298841Sgshapiro { "OPTIONAL", D_OPTIONAL }, 184398841Sgshapiro { "DISABLE", D_DISABLE }, 184498841Sgshapiro { "ISSET", D_ISSET }, 184598841Sgshapiro { NULL, 0 } 184698841Sgshapiro}; 184798841Sgshapiro 184898841Sgshapirostatic void 184998841Sgshapiroprintdaemonflags(d) 185098841Sgshapiro DAEMON_T *d; 185198841Sgshapiro{ 185298841Sgshapiro register struct dflags *df; 185398841Sgshapiro bool first = true; 185498841Sgshapiro 185598841Sgshapiro for (df = DaemonFlags; df->d_name != NULL; df++) 185698841Sgshapiro { 185798841Sgshapiro if (!bitnset(df->d_flag, d->d_flags)) 185898841Sgshapiro continue; 185998841Sgshapiro if (first) 1860132943Sgshapiro sm_dprintf("<%s", df->d_name); 186198841Sgshapiro else 1862132943Sgshapiro sm_dprintf(",%s", df->d_name); 186398841Sgshapiro first = false; 186498841Sgshapiro } 186598841Sgshapiro if (!first) 1866132943Sgshapiro sm_dprintf(">"); 186798841Sgshapiro} 186898841Sgshapiro 186964562Sgshapirobool 187064562Sgshapirosetdaemonoptions(p) 187164562Sgshapiro register char *p; 187264562Sgshapiro{ 187390792Sgshapiro if (NDaemons >= MAXDAEMONS) 187490792Sgshapiro return false; 187590792Sgshapiro Daemons[NDaemons].d_socket = -1; 187690792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 187790792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 187890792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 187964562Sgshapiro 188090792Sgshapiro#if MILTER 188190792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 188290792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 188390792Sgshapiro#endif /* MILTER */ 188490792Sgshapiro 188590792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 188690792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 188764562Sgshapiro else 188864562Sgshapiro { 188964562Sgshapiro char num[30]; 189064562Sgshapiro 1891168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Daemon%d", NDaemons); 189290792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 189364562Sgshapiro } 189464562Sgshapiro 189564562Sgshapiro if (tTd(37, 1)) 189664562Sgshapiro { 189790792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 189898841Sgshapiro printdaemonflags(&Daemons[NDaemons]); 189990792Sgshapiro sm_dprintf("\n"); 190064562Sgshapiro } 190190792Sgshapiro ++NDaemons; 190290792Sgshapiro return true; 190364562Sgshapiro} 190490792Sgshapiro/* 190564562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 190664562Sgshapiro** 190764562Sgshapiro** Parameters: 190864562Sgshapiro** none 190964562Sgshapiro** 191064562Sgshapiro** Returns: 191164562Sgshapiro** none 191264562Sgshapiro** 191364562Sgshapiro** Side Effects: 191464562Sgshapiro** initializes structure for one daemon. 191564562Sgshapiro*/ 191690792Sgshapiro 191764562Sgshapirovoid 191864562Sgshapiroinitdaemon() 191964562Sgshapiro{ 192090792Sgshapiro if (NDaemons == 0) 192164562Sgshapiro { 192290792Sgshapiro Daemons[NDaemons].d_socket = -1; 192390792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 192490792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 192590792Sgshapiro NDaemons = 1; 192664562Sgshapiro } 192764562Sgshapiro} 192890792Sgshapiro/* 192964562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 193064562Sgshapiro** 193164562Sgshapiro** Parameters: 193264562Sgshapiro** p -- the options line. 193364562Sgshapiro** 193464562Sgshapiro** Returns: 193564562Sgshapiro** none. 193664562Sgshapiro*/ 193764562Sgshapiro 193890792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 193964562Sgshapiro 194064562Sgshapirovoid 194164562Sgshapirosetclientoptions(p) 194264562Sgshapiro register char *p; 194364562Sgshapiro{ 194490792Sgshapiro int family; 194590792Sgshapiro DAEMON_T d; 194664562Sgshapiro 1947168515Sgshapiro memset(&d, '\0', sizeof(d)); 194864562Sgshapiro setsockaddroptions(p, &d); 194964562Sgshapiro 195064562Sgshapiro /* grab what we need */ 195190792Sgshapiro family = d.d_addr.sa.sa_family; 195290792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 195390792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 195490792Sgshapiro if (d.d_name != NULL) 195590792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 195664562Sgshapiro else 195790792Sgshapiro { 195890792Sgshapiro char num[30]; 195990792Sgshapiro 1960168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Client%d", family); 196190792Sgshapiro ClientSettings[family].d_name = newstr(num); 196290792Sgshapiro } 196364562Sgshapiro} 196490792Sgshapiro/* 196564562Sgshapiro** ADDR_FAMILY -- determine address family from address 196664562Sgshapiro** 196764562Sgshapiro** Parameters: 196864562Sgshapiro** addr -- the string representation of the address 196964562Sgshapiro** 197064562Sgshapiro** Returns: 197164562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 197264562Sgshapiro** 197364562Sgshapiro** Side Effects: 197464562Sgshapiro** none. 197564562Sgshapiro*/ 197664562Sgshapiro 197764562Sgshapirostatic int 197864562Sgshapiroaddr_family(addr) 197964562Sgshapiro char *addr; 198064562Sgshapiro{ 198190792Sgshapiro#if NETINET6 198264562Sgshapiro SOCKADDR clt_addr; 198390792Sgshapiro#endif /* NETINET6 */ 198464562Sgshapiro 198590792Sgshapiro#if NETINET 198664562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 198764562Sgshapiro { 198864562Sgshapiro if (tTd(16, 9)) 198990792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 199064562Sgshapiro return AF_INET; 199164562Sgshapiro } 199290792Sgshapiro#endif /* NETINET */ 199390792Sgshapiro#if NETINET6 199490792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 199564562Sgshapiro { 199664562Sgshapiro if (tTd(16, 9)) 199790792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 199864562Sgshapiro return AF_INET6; 199964562Sgshapiro } 200090792Sgshapiro#endif /* NETINET6 */ 200190792Sgshapiro#if _FFR_DAEMON_NETUNIX 200290792Sgshapiro# if NETUNIX 200390792Sgshapiro if (*addr == '/') 200490792Sgshapiro { 200590792Sgshapiro if (tTd(16, 9)) 200690792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 200790792Sgshapiro return AF_UNIX; 200890792Sgshapiro } 200990792Sgshapiro# endif /* NETUNIX */ 201090792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 201164562Sgshapiro if (tTd(16, 9)) 201290792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 201364562Sgshapiro return AF_UNSPEC; 201464562Sgshapiro} 201590792Sgshapiro 201690792Sgshapiro/* 201790792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 201890792Sgshapiro** 201990792Sgshapiro** Parameters: 202090792Sgshapiro** flag -- the flag to test. 202190792Sgshapiro** 202290792Sgshapiro** Returns: 202390792Sgshapiro** true iff all configured clients have set the flag. 202490792Sgshapiro*/ 202590792Sgshapiro 202690792Sgshapirobool 202790792Sgshapirochkclientmodifiers(flag) 202890792Sgshapiro int flag; 202990792Sgshapiro{ 203090792Sgshapiro int i; 203190792Sgshapiro bool flagisset; 203290792Sgshapiro 203390792Sgshapiro flagisset = false; 203490792Sgshapiro for (i = 0; i < AF_MAX; i++) 203590792Sgshapiro { 203690792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 203790792Sgshapiro { 203890792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 203990792Sgshapiro return false; 204090792Sgshapiro flagisset = true; 204190792Sgshapiro } 204290792Sgshapiro } 204390792Sgshapiro return flagisset; 204490792Sgshapiro} 204590792Sgshapiro 204690792Sgshapiro#if MILTER 204790792Sgshapiro/* 204890792Sgshapiro** SETUP_DAEMON_FILTERS -- Parse per-socket filters 204990792Sgshapiro** 205090792Sgshapiro** Parameters: 205190792Sgshapiro** none 205290792Sgshapiro** 205390792Sgshapiro** Returns: 205490792Sgshapiro** none 205590792Sgshapiro*/ 205690792Sgshapiro 205790792Sgshapirovoid 205890792Sgshapirosetup_daemon_milters() 205990792Sgshapiro{ 206090792Sgshapiro int idx; 206190792Sgshapiro 206290792Sgshapiro if (OpMode == MD_SMTP) 206390792Sgshapiro { 206490792Sgshapiro /* no need to configure the daemons */ 206590792Sgshapiro return; 206690792Sgshapiro } 206790792Sgshapiro 206890792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 206990792Sgshapiro { 207090792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 207190792Sgshapiro { 207290792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 207390792Sgshapiro Daemons[idx].d_inputfilters, 207490792Sgshapiro MAXFILTERS); 207590792Sgshapiro } 207690792Sgshapiro } 207790792Sgshapiro} 207890792Sgshapiro#endif /* MILTER */ 207990792Sgshapiro/* 208064562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 208164562Sgshapiro** 208264562Sgshapiro** Parameters: 208338032Speter** host -- the name of the host. 208438032Speter** port -- the port number to connect to. 208538032Speter** mci -- a pointer to the mail connection information 208638032Speter** structure to be filled in. 208738032Speter** e -- the current envelope. 208890792Sgshapiro** enough -- time at which to stop further connection attempts. 208990792Sgshapiro** (0 means no limit) 209038032Speter** 209138032Speter** Returns: 209238032Speter** An exit code telling whether the connection could be 209338032Speter** made and if not why not. 209438032Speter** 209538032Speter** Side Effects: 209638032Speter** none. 209738032Speter*/ 209838032Speter 209938032Speterstatic jmp_buf CtxConnectTimeout; 210038032Speter 210138032SpeterSOCKADDR CurHostAddr; /* address of current host */ 210238032Speter 210338032Speterint 210490792Sgshapiromakeconnection(host, port, mci, e, enough) 210538032Speter char *host; 210690792Sgshapiro volatile unsigned int port; 210738032Speter register MCI *mci; 210838032Speter ENVELOPE *e; 210990792Sgshapiro time_t enough; 211038032Speter{ 211138032Speter register volatile int addrno = 0; 211290792Sgshapiro volatile int s; 211390792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 211438032Speter SOCKADDR addr; 211564562Sgshapiro SOCKADDR clt_addr; 211664562Sgshapiro int save_errno = 0; 211764562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 2118159609Sgshapiro volatile bool firstconnect = true; 211990792Sgshapiro SM_EVENT *volatile ev = NULL; 212090792Sgshapiro#if NETINET6 212190792Sgshapiro volatile bool v6found = false; 212290792Sgshapiro#endif /* NETINET6 */ 212364562Sgshapiro volatile int family = InetMode; 212464562Sgshapiro SOCKADDR_LEN_T len; 212564562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 212664562Sgshapiro volatile bool clt_bind; 212764562Sgshapiro BITMAP256 d_flags; 212864562Sgshapiro char *p; 212964562Sgshapiro extern ENVELOPE BlankEnvelope; 213038032Speter 213190792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 213264562Sgshapiro clrbitmap(d_flags); 213390792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 213464562Sgshapiro { 213564562Sgshapiro for (; *p != '\0'; p++) 213664562Sgshapiro { 213764562Sgshapiro if (!(isascii(*p) && isspace(*p))) 213871345Sgshapiro setbitn(bitidx(*p), d_flags); 213964562Sgshapiro } 214064562Sgshapiro } 214164562Sgshapiro 214290792Sgshapiro#if NETINET6 214364562Sgshapiro v4retry: 214490792Sgshapiro#endif /* NETINET6 */ 214590792Sgshapiro clt_bind = false; 214664562Sgshapiro 214764562Sgshapiro /* Set up the address for outgoing connection. */ 214864562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 214990792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 215073188Sgshapiro *p != '\0') 215164562Sgshapiro { 215290792Sgshapiro#if NETINET6 215364562Sgshapiro char p6[INET6_ADDRSTRLEN]; 215490792Sgshapiro#endif /* NETINET6 */ 215564562Sgshapiro 2156168515Sgshapiro memset(&clt_addr, '\0', sizeof(clt_addr)); 215764562Sgshapiro 215864562Sgshapiro /* infer the address family from the address itself */ 215964562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 216064562Sgshapiro switch (clt_addr.sa.sa_family) 216164562Sgshapiro { 216290792Sgshapiro#if NETINET 216364562Sgshapiro case AF_INET: 216473188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 216573188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 2166203004Sgshapiro clt_addr.sin.sin_addr.s_addr != 2167203004Sgshapiro htonl(INADDR_LOOPBACK)) 216864562Sgshapiro { 216990792Sgshapiro clt_bind = true; 2170168515Sgshapiro socksize = sizeof(struct sockaddr_in); 217164562Sgshapiro } 217264562Sgshapiro break; 217390792Sgshapiro#endif /* NETINET */ 217464562Sgshapiro 217590792Sgshapiro#if NETINET6 217664562Sgshapiro case AF_INET6: 217764562Sgshapiro if (inet_addr(p) != INADDR_NONE) 2178168515Sgshapiro (void) sm_snprintf(p6, sizeof(p6), 217990792Sgshapiro "IPv6:::ffff:%s", p); 218064562Sgshapiro else 2181168515Sgshapiro (void) sm_strlcpy(p6, p, sizeof(p6)); 218290792Sgshapiro if (anynet_pton(AF_INET6, p6, 218390792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 218473188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 218564562Sgshapiro { 218690792Sgshapiro clt_bind = true; 2187168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 218864562Sgshapiro } 218964562Sgshapiro break; 219090792Sgshapiro#endif /* NETINET6 */ 219164562Sgshapiro 219290792Sgshapiro#if 0 219364562Sgshapiro default: 219464562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 219564562Sgshapiro clt_addr.sa.sa_family); 219664562Sgshapiro break; 219790792Sgshapiro#endif /* 0 */ 219864562Sgshapiro } 219964562Sgshapiro if (clt_bind) 220064562Sgshapiro family = clt_addr.sa.sa_family; 220164562Sgshapiro } 220290792Sgshapiro 220390792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 220490792Sgshapiro if (!clt_bind) 220564562Sgshapiro { 220690792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 220764562Sgshapiro switch (clt_addr.sa.sa_family) 220864562Sgshapiro { 220990792Sgshapiro#if NETINET 221064562Sgshapiro case AF_INET: 221164562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 2212182352Sgshapiro clt_addr.sin.sin_addr.s_addr = LocalDaemon ? 2213182352Sgshapiro htonl(INADDR_LOOPBACK) : INADDR_ANY; 221464562Sgshapiro else 221590792Sgshapiro clt_bind = true; 221664562Sgshapiro if (clt_addr.sin.sin_port != 0) 221790792Sgshapiro clt_bind = true; 2218168515Sgshapiro socksize = sizeof(struct sockaddr_in); 221964562Sgshapiro break; 222090792Sgshapiro#endif /* NETINET */ 222190792Sgshapiro#if NETINET6 222264562Sgshapiro case AF_INET6: 222364562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 2224223067Sgshapiro clt_addr.sin6.sin6_addr = 2225223067Sgshapiro (LocalDaemon && V6LoopbackAddrFound) ? 2226182352Sgshapiro in6addr_loopback : in6addr_any; 222764562Sgshapiro else 222890792Sgshapiro clt_bind = true; 2229168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 223064562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 223190792Sgshapiro clt_bind = true; 223264562Sgshapiro break; 223390792Sgshapiro#endif /* NETINET6 */ 223490792Sgshapiro#if NETISO 223564562Sgshapiro case AF_ISO: 2236168515Sgshapiro socksize = sizeof(clt_addr.siso); 223790792Sgshapiro clt_bind = true; 223864562Sgshapiro break; 223990792Sgshapiro#endif /* NETISO */ 224064562Sgshapiro default: 224164562Sgshapiro break; 224264562Sgshapiro } 224364562Sgshapiro } 224464562Sgshapiro 224538032Speter /* 224638032Speter ** Set up the address for the mailer. 224738032Speter ** Accept "[a.b.c.d]" syntax for host name. 224838032Speter */ 224938032Speter 225073188Sgshapiro SM_SET_H_ERRNO(0); 225138032Speter errno = 0; 2252168515Sgshapiro memset(&CurHostAddr, '\0', sizeof(CurHostAddr)); 2253168515Sgshapiro memset(&addr, '\0', sizeof(addr)); 225438032Speter SmtpPhase = mci->mci_phase = "initial connection"; 225538032Speter CurHostName = host; 225638032Speter 225738032Speter if (host[0] == '[') 225838032Speter { 225964562Sgshapiro p = strchr(host, ']'); 226038032Speter if (p != NULL) 226138032Speter { 226290792Sgshapiro#if NETINET 226364562Sgshapiro unsigned long hid = INADDR_NONE; 226490792Sgshapiro#endif /* NETINET */ 226590792Sgshapiro#if NETINET6 226664562Sgshapiro struct sockaddr_in6 hid6; 226790792Sgshapiro#endif /* NETINET6 */ 226864562Sgshapiro 226938032Speter *p = '\0'; 227090792Sgshapiro#if NETINET6 2271168515Sgshapiro memset(&hid6, '\0', sizeof(hid6)); 227290792Sgshapiro#endif /* NETINET6 */ 227390792Sgshapiro#if NETINET 227464562Sgshapiro if (family == AF_INET && 227564562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 227638032Speter { 227764562Sgshapiro addr.sin.sin_family = AF_INET; 227864562Sgshapiro addr.sin.sin_addr.s_addr = hid; 227964562Sgshapiro } 228064562Sgshapiro else 228190792Sgshapiro#endif /* NETINET */ 228290792Sgshapiro#if NETINET6 228364562Sgshapiro if (family == AF_INET6 && 228490792Sgshapiro anynet_pton(AF_INET6, &host[1], 228590792Sgshapiro &hid6.sin6_addr) == 1) 228664562Sgshapiro { 228764562Sgshapiro addr.sin6.sin6_family = AF_INET6; 228864562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 228964562Sgshapiro } 229064562Sgshapiro else 229190792Sgshapiro#endif /* NETINET6 */ 229264562Sgshapiro { 229338032Speter /* try it as a host name (avoid MX lookup) */ 229464562Sgshapiro hp = sm_gethostbyname(&host[1], family); 229538032Speter if (hp == NULL && p[-1] == '.') 229638032Speter { 229790792Sgshapiro#if NAMED_BIND 229838032Speter int oldopts = _res.options; 229938032Speter 230038032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 230190792Sgshapiro#endif /* NAMED_BIND */ 230238032Speter p[-1] = '\0'; 230364562Sgshapiro hp = sm_gethostbyname(&host[1], 230464562Sgshapiro family); 230538032Speter p[-1] = '.'; 230690792Sgshapiro#if NAMED_BIND 230738032Speter _res.options = oldopts; 230890792Sgshapiro#endif /* NAMED_BIND */ 230938032Speter } 231038032Speter *p = ']'; 231138032Speter goto gothostent; 231238032Speter } 231338032Speter *p = ']'; 231438032Speter } 231538032Speter if (p == NULL) 231638032Speter { 231738032Speter extern char MsgBuf[]; 231838032Speter 231964562Sgshapiro usrerrenh("5.1.2", 232064562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 232164562Sgshapiro host); 232238032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 232364562Sgshapiro errno = EINVAL; 232438032Speter return EX_NOHOST; 232538032Speter } 232638032Speter } 232738032Speter else 232838032Speter { 232938032Speter /* contortion to get around SGI cc complaints */ 233038032Speter { 233164562Sgshapiro p = &host[strlen(host) - 1]; 233264562Sgshapiro hp = sm_gethostbyname(host, family); 233338032Speter if (hp == NULL && *p == '.') 233438032Speter { 233590792Sgshapiro#if NAMED_BIND 233638032Speter int oldopts = _res.options; 233738032Speter 233838032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 233990792Sgshapiro#endif /* NAMED_BIND */ 234038032Speter *p = '\0'; 234164562Sgshapiro hp = sm_gethostbyname(host, family); 234238032Speter *p = '.'; 234390792Sgshapiro#if NAMED_BIND 234438032Speter _res.options = oldopts; 234590792Sgshapiro#endif /* NAMED_BIND */ 234638032Speter } 234738032Speter } 234838032Spetergothostent: 2349203004Sgshapiro if (hp == NULL || hp->h_addr == NULL) 235038032Speter { 235190792Sgshapiro#if NAMED_BIND 235238032Speter /* check for name server timeouts */ 235390792Sgshapiro# if NETINET6 235490792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 2355261370Sgshapiro (h_errno == TRY_AGAIN || errno == ETIMEDOUT)) 235638032Speter { 235790792Sgshapiro /* 235890792Sgshapiro ** An attempt with family AF_INET may 2359261370Sgshapiro ** succeed. By skipping the next section 236090792Sgshapiro ** of code, we will try AF_INET before 236190792Sgshapiro ** failing. 236290792Sgshapiro */ 236390792Sgshapiro 236490792Sgshapiro if (tTd(16, 10)) 236590792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 236638032Speter } 236790792Sgshapiro else 236890792Sgshapiro# endif /* NETINET6 */ 236990792Sgshapiro { 237090792Sgshapiro if (errno == ETIMEDOUT || 2371168515Sgshapiro# if _FFR_GETHBN_ExFILE 2372168515Sgshapiro# ifdef EMFILE 2373168515Sgshapiro errno == EMFILE || 2374168515Sgshapiro# endif /* EMFILE */ 2375168515Sgshapiro# ifdef ENFILE 2376168515Sgshapiro errno == ENFILE || 2377168515Sgshapiro# endif /* ENFILE */ 2378168515Sgshapiro# endif /* _FFR_GETHBN_ExFILE */ 237990792Sgshapiro h_errno == TRY_AGAIN || 238090792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 238190792Sgshapiro { 238290792Sgshapiro save_errno = errno; 238390792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 238490792Sgshapiro "4.4.3", NULL); 238590792Sgshapiro errno = save_errno; 238690792Sgshapiro return EX_TEMPFAIL; 238790792Sgshapiro } 238890792Sgshapiro } 238990792Sgshapiro#endif /* NAMED_BIND */ 239090792Sgshapiro#if NETINET6 239164562Sgshapiro /* 239264562Sgshapiro ** Try v6 first, then fall back to v4. 239364562Sgshapiro ** If we found a v6 address, but no v4 239464562Sgshapiro ** addresses, then TEMPFAIL. 239564562Sgshapiro */ 239664562Sgshapiro 239764562Sgshapiro if (family == AF_INET6) 239864562Sgshapiro { 239964562Sgshapiro family = AF_INET; 240064562Sgshapiro goto v4retry; 240164562Sgshapiro } 240264562Sgshapiro if (v6found) 240364562Sgshapiro goto v6tempfail; 240490792Sgshapiro#endif /* NETINET6 */ 240564562Sgshapiro save_errno = errno; 240638032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 240764562Sgshapiro errno = save_errno; 240864562Sgshapiro return EX_NOHOST; 240938032Speter } 241038032Speter addr.sa.sa_family = hp->h_addrtype; 241138032Speter switch (hp->h_addrtype) 241238032Speter { 241390792Sgshapiro#if NETINET 241438032Speter case AF_INET: 241564562Sgshapiro memmove(&addr.sin.sin_addr, 241664562Sgshapiro hp->h_addr, 241738032Speter INADDRSZ); 241838032Speter break; 241990792Sgshapiro#endif /* NETINET */ 242038032Speter 242190792Sgshapiro#if NETINET6 242264562Sgshapiro case AF_INET6: 242364562Sgshapiro memmove(&addr.sin6.sin6_addr, 242464562Sgshapiro hp->h_addr, 242564562Sgshapiro IN6ADDRSZ); 242664562Sgshapiro break; 242790792Sgshapiro#endif /* NETINET6 */ 242864562Sgshapiro 242938032Speter default: 2430168515Sgshapiro if (hp->h_length > sizeof(addr.sa.sa_data)) 243138032Speter { 243238032Speter syserr("makeconnection: long sa_data: family %d len %d", 243338032Speter hp->h_addrtype, hp->h_length); 243438032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 243564562Sgshapiro errno = EINVAL; 243638032Speter return EX_NOHOST; 243738032Speter } 243890792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 243938032Speter break; 244038032Speter } 244138032Speter addrno = 1; 244238032Speter } 244338032Speter 244438032Speter /* 244538032Speter ** Determine the port number. 244638032Speter */ 244738032Speter 244838032Speter if (port == 0) 244938032Speter { 245090792Sgshapiro#ifdef NO_GETSERVBYNAME 245164562Sgshapiro port = htons(25); 245290792Sgshapiro#else /* NO_GETSERVBYNAME */ 245338032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 245438032Speter 245538032Speter if (sp == NULL) 245638032Speter { 245738032Speter if (LogLevel > 2) 245838032Speter sm_syslog(LOG_ERR, NOQID, 245964562Sgshapiro "makeconnection: service \"smtp\" unknown"); 246038032Speter port = htons(25); 246138032Speter } 246238032Speter else 246338032Speter port = sp->s_port; 246490792Sgshapiro#endif /* NO_GETSERVBYNAME */ 246538032Speter } 246638032Speter 246790792Sgshapiro#if NETINET6 246890792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 246990792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 247090792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 247190792Sgshapiro { 247290792Sgshapiro /* 247390792Sgshapiro ** Ignore mapped IPv4 address since 247490792Sgshapiro ** there is a ClientPortOptions setting 247590792Sgshapiro ** for IPv4. 247690792Sgshapiro */ 247790792Sgshapiro 247890792Sgshapiro goto nextaddr; 247990792Sgshapiro } 248090792Sgshapiro#endif /* NETINET6 */ 248190792Sgshapiro 248238032Speter switch (addr.sa.sa_family) 248338032Speter { 248490792Sgshapiro#if NETINET 248538032Speter case AF_INET: 248638032Speter addr.sin.sin_port = port; 2487168515Sgshapiro addrlen = sizeof(struct sockaddr_in); 248838032Speter break; 248990792Sgshapiro#endif /* NETINET */ 249038032Speter 249190792Sgshapiro#if NETINET6 249264562Sgshapiro case AF_INET6: 249364562Sgshapiro addr.sin6.sin6_port = port; 2494168515Sgshapiro addrlen = sizeof(struct sockaddr_in6); 249564562Sgshapiro break; 249690792Sgshapiro#endif /* NETINET6 */ 249764562Sgshapiro 249890792Sgshapiro#if NETISO 249938032Speter case AF_ISO: 250038032Speter /* assume two byte transport selector */ 250164562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 2502168515Sgshapiro addrlen = sizeof(struct sockaddr_iso); 250338032Speter break; 250490792Sgshapiro#endif /* NETISO */ 250538032Speter 250638032Speter default: 250738032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 250838032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 250964562Sgshapiro errno = EINVAL; 251090792Sgshapiro#if NETINET6 251171345Sgshapiro if (hp != NULL) 251271345Sgshapiro freehostent(hp); 251390792Sgshapiro#endif /* NETINET6 */ 251464562Sgshapiro return EX_NOHOST; 251538032Speter } 251638032Speter 251738032Speter /* 251838032Speter ** Try to actually open the connection. 251938032Speter */ 252038032Speter 252190792Sgshapiro#if XLA 252238032Speter /* if too many connections, don't bother trying */ 252338032Speter if (!xla_noqueue_ok(host)) 252471345Sgshapiro { 252590792Sgshapiro# if NETINET6 252671345Sgshapiro if (hp != NULL) 252771345Sgshapiro freehostent(hp); 252890792Sgshapiro# endif /* NETINET6 */ 252938032Speter return EX_TEMPFAIL; 253071345Sgshapiro } 253190792Sgshapiro#endif /* XLA */ 253238032Speter 253338032Speter for (;;) 253438032Speter { 253538032Speter if (tTd(16, 1)) 253690792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 253790792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 253890792Sgshapiro (int) addr.sa.sa_family); 253938032Speter 254038032Speter /* save for logging */ 254138032Speter CurHostAddr = addr; 254238032Speter 254390792Sgshapiro#if HASRRESVPORT 254438032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 254538032Speter { 254638032Speter int rport = IPPORT_RESERVED - 1; 254738032Speter 254838032Speter s = rresvport(&rport); 254938032Speter } 255038032Speter else 255190792Sgshapiro#endif /* HASRRESVPORT */ 255238032Speter { 255390792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 255438032Speter } 255538032Speter if (s < 0) 255638032Speter { 255764562Sgshapiro save_errno = errno; 255838032Speter syserr("makeconnection: cannot create socket"); 255990792Sgshapiro#if XLA 256038032Speter xla_host_end(host); 256190792Sgshapiro#endif /* XLA */ 256238032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 256390792Sgshapiro#if NETINET6 256471345Sgshapiro if (hp != NULL) 256571345Sgshapiro freehostent(hp); 256690792Sgshapiro#endif /* NETINET6 */ 256764562Sgshapiro errno = save_errno; 256838032Speter return EX_TEMPFAIL; 256938032Speter } 257038032Speter 257190792Sgshapiro#ifdef SO_SNDBUF 257290792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 257338032Speter { 257438032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 257590792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 257690792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 257738032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 257838032Speter } 257990792Sgshapiro#endif /* SO_SNDBUF */ 258090792Sgshapiro#ifdef SO_RCVBUF 258190792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 258264562Sgshapiro { 258364562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 258490792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 258590792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 258664562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 258764562Sgshapiro } 258890792Sgshapiro#endif /* SO_RCVBUF */ 258938032Speter 259038032Speter if (tTd(16, 1)) 259190792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 259238032Speter 259338032Speter /* turn on network debugging? */ 259438032Speter if (tTd(16, 101)) 259538032Speter { 259638032Speter int on = 1; 259764562Sgshapiro 259838032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 2599168515Sgshapiro (char *)&on, sizeof(on)); 260038032Speter } 260190792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 260290792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 260390792Sgshapiro errno = 0; /* for debugging */ 260438032Speter 260564562Sgshapiro if (clt_bind) 260664562Sgshapiro { 260764562Sgshapiro int on = 1; 260864562Sgshapiro 260964562Sgshapiro switch (clt_addr.sa.sa_family) 261064562Sgshapiro { 261190792Sgshapiro#if NETINET 261264562Sgshapiro case AF_INET: 261364562Sgshapiro if (clt_addr.sin.sin_port != 0) 261464562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 261564562Sgshapiro SO_REUSEADDR, 261664562Sgshapiro (char *) &on, 2617168515Sgshapiro sizeof(on)); 261864562Sgshapiro break; 261990792Sgshapiro#endif /* NETINET */ 262064562Sgshapiro 262190792Sgshapiro#if NETINET6 262264562Sgshapiro case AF_INET6: 262364562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 262464562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 262564562Sgshapiro SO_REUSEADDR, 262664562Sgshapiro (char *) &on, 2627168515Sgshapiro sizeof(on)); 262864562Sgshapiro break; 262990792Sgshapiro#endif /* NETINET6 */ 263064562Sgshapiro } 263164562Sgshapiro 263264562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 263364562Sgshapiro { 263464562Sgshapiro save_errno = errno; 263564562Sgshapiro (void) close(s); 263664562Sgshapiro errno = save_errno; 263764562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 263864562Sgshapiro anynet_ntoa(&clt_addr)); 263990792Sgshapiro#if NETINET6 264071345Sgshapiro if (hp != NULL) 264171345Sgshapiro freehostent(hp); 264290792Sgshapiro#endif /* NETINET6 */ 264364562Sgshapiro errno = save_errno; 264464562Sgshapiro return EX_TEMPFAIL; 264564562Sgshapiro } 264664562Sgshapiro } 264764562Sgshapiro 264838032Speter /* 264938032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 265038032Speter ** Time out the connect to avoid this problem. 265138032Speter */ 265238032Speter 265338032Speter if (setjmp(CtxConnectTimeout) == 0) 265438032Speter { 265538032Speter int i; 265638032Speter 265738032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 265890792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 265990792Sgshapiro connecttimeout, 0); 266038032Speter else if (TimeOuts.to_connect != 0) 266190792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 266290792Sgshapiro connecttimeout, 0); 266338032Speter else 266438032Speter ev = NULL; 266538032Speter 266664562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 266764562Sgshapiro { 266890792Sgshapiro#if NETINET 266964562Sgshapiro case AF_INET: 267064562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 2671223067Sgshapiro addr.sa.sa_family = ConnectOnlyTo.sa.sa_family; 267264562Sgshapiro break; 267390792Sgshapiro#endif /* NETINET */ 267464562Sgshapiro 267590792Sgshapiro#if NETINET6 267664562Sgshapiro case AF_INET6: 267764562Sgshapiro memmove(&addr.sin6.sin6_addr, 267864562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 267964562Sgshapiro IN6ADDRSZ); 268064562Sgshapiro break; 268190792Sgshapiro#endif /* NETINET6 */ 268264562Sgshapiro } 2683141858Sgshapiro if (tTd(16, 1)) 2684141858Sgshapiro sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr)); 268538032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 268664562Sgshapiro save_errno = errno; 268738032Speter if (ev != NULL) 268890792Sgshapiro sm_clrevent(ev); 268938032Speter if (i >= 0) 269038032Speter break; 269138032Speter } 269238032Speter else 269364562Sgshapiro save_errno = errno; 269438032Speter 269594334Sgshapiro /* couldn't connect.... figure out why */ 269694334Sgshapiro (void) close(s); 269794334Sgshapiro 269838032Speter /* if running demand-dialed connection, try again */ 269990792Sgshapiro if (DialDelay > 0 && firstconnect && 270090792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 270138032Speter { 270238032Speter if (tTd(16, 1)) 270390792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 270490792Sgshapiro sm_errstring(save_errno)); 270590792Sgshapiro firstconnect = false; 270664562Sgshapiro (void) sleep(DialDelay); 270738032Speter continue; 270838032Speter } 270938032Speter 271090792Sgshapiro if (LogLevel > 13) 271138032Speter sm_syslog(LOG_INFO, e->e_id, 271238032Speter "makeconnection (%s [%s]) failed: %s", 271338032Speter host, anynet_ntoa(&addr), 271490792Sgshapiro sm_errstring(save_errno)); 271538032Speter 271690792Sgshapiro#if NETINET6 271790792Sgshapironextaddr: 271890792Sgshapiro#endif /* NETINET6 */ 271990792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 272090792Sgshapiro (enough == 0 || curtime() < enough)) 272138032Speter { 272238032Speter if (tTd(16, 1)) 272390792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 272490792Sgshapiro sm_errstring(save_errno)); 272538032Speter switch (addr.sa.sa_family) 272638032Speter { 272790792Sgshapiro#if NETINET 272838032Speter case AF_INET: 272964562Sgshapiro memmove(&addr.sin.sin_addr, 273064562Sgshapiro hp->h_addr_list[addrno++], 273164562Sgshapiro INADDRSZ); 273238032Speter break; 273390792Sgshapiro#endif /* NETINET */ 273438032Speter 273590792Sgshapiro#if NETINET6 273664562Sgshapiro case AF_INET6: 273764562Sgshapiro memmove(&addr.sin6.sin6_addr, 273864562Sgshapiro hp->h_addr_list[addrno++], 273964562Sgshapiro IN6ADDRSZ); 274064562Sgshapiro break; 274190792Sgshapiro#endif /* NETINET6 */ 274264562Sgshapiro 274338032Speter default: 274464562Sgshapiro memmove(addr.sa.sa_data, 274564562Sgshapiro hp->h_addr_list[addrno++], 274638032Speter hp->h_length); 274738032Speter break; 274838032Speter } 274938032Speter continue; 275038032Speter } 275164562Sgshapiro errno = save_errno; 275238032Speter 275390792Sgshapiro#if NETINET6 275464562Sgshapiro if (family == AF_INET6) 275564562Sgshapiro { 275664562Sgshapiro if (tTd(16, 1)) 275790792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 275890792Sgshapiro sm_errstring(save_errno)); 275990792Sgshapiro v6found = true; 276064562Sgshapiro family = AF_INET; 276171345Sgshapiro if (hp != NULL) 276271345Sgshapiro { 276371345Sgshapiro freehostent(hp); 276471345Sgshapiro hp = NULL; 276571345Sgshapiro } 276664562Sgshapiro goto v4retry; 276764562Sgshapiro } 276864562Sgshapiro v6tempfail: 276990792Sgshapiro#endif /* NETINET6 */ 277038032Speter /* couldn't open connection */ 277190792Sgshapiro#if NETINET6 277264562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 277364562Sgshapiro if (errno > 0) 277490792Sgshapiro#endif /* NETINET6 */ 277564562Sgshapiro save_errno = errno; 277664562Sgshapiro if (tTd(16, 1)) 277790792Sgshapiro sm_dprintf("Connect failed (%s)\n", 277890792Sgshapiro sm_errstring(save_errno)); 277990792Sgshapiro#if XLA 278038032Speter xla_host_end(host); 278190792Sgshapiro#endif /* XLA */ 278238032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 278390792Sgshapiro#if NETINET6 278471345Sgshapiro if (hp != NULL) 278571345Sgshapiro freehostent(hp); 278690792Sgshapiro#endif /* NETINET6 */ 278764562Sgshapiro errno = save_errno; 278838032Speter return EX_TEMPFAIL; 278938032Speter } 279038032Speter 279190792Sgshapiro#if NETINET6 279271345Sgshapiro if (hp != NULL) 279371345Sgshapiro { 279471345Sgshapiro freehostent(hp); 279571345Sgshapiro hp = NULL; 279671345Sgshapiro } 279790792Sgshapiro#endif /* NETINET6 */ 279871345Sgshapiro 279938032Speter /* connection ok, put it into canonical form */ 280064562Sgshapiro mci->mci_out = NULL; 280190792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 280290792Sgshapiro (void *) &s, 2803132943Sgshapiro SM_IO_WRONLY_B, NULL)) == NULL || 280438032Speter (s = dup(s)) < 0 || 280590792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 280690792Sgshapiro (void *) &s, 2807132943Sgshapiro SM_IO_RDONLY_B, NULL)) == NULL) 280838032Speter { 280964562Sgshapiro save_errno = errno; 281038032Speter syserr("cannot open SMTP client channel, fd=%d", s); 281138032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 281264562Sgshapiro if (mci->mci_out != NULL) 281390792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 281464562Sgshapiro (void) close(s); 281564562Sgshapiro errno = save_errno; 281638032Speter return EX_TEMPFAIL; 281738032Speter } 281890792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 281938032Speter 282090792Sgshapiro /* set {client_flags} */ 282190792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 282290792Sgshapiro { 282390792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 282490792Sgshapiro macid("{client_flags}"), 282590792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 282690792Sgshapiro } 282790792Sgshapiro else 282890792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 282990792Sgshapiro macid("{client_flags}"), ""); 283090792Sgshapiro 283190792Sgshapiro /* "add" {client_flags} to bitmap */ 283290792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 283390792Sgshapiro { 283490792Sgshapiro /* look for just this one flag */ 283590792Sgshapiro setbitn(D_IFNHELO, d_flags); 283690792Sgshapiro } 283790792Sgshapiro 283864562Sgshapiro /* find out name for Interface through which we connect */ 2839168515Sgshapiro len = sizeof(addr); 284064562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 284164562Sgshapiro { 284264562Sgshapiro char *name; 284390792Sgshapiro char family[5]; 284464562Sgshapiro 284590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 284690792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 284790792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 284890792Sgshapiro addr.sa.sa_family); 284990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 285090792Sgshapiro macid("{if_family_out}"), family); 285164562Sgshapiro 285264562Sgshapiro name = hostnamebyanyaddr(&addr); 285390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 285490792Sgshapiro macid("{if_name_out}"), name); 285564562Sgshapiro if (LogLevel > 11) 285664562Sgshapiro { 285764562Sgshapiro /* log connection information */ 285864562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 285964562Sgshapiro "SMTP outgoing connect on %.40s", name); 286064562Sgshapiro } 286164562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 286264562Sgshapiro { 286364562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 286464562Sgshapiro mci->mci_heloname = newstr(name); 286564562Sgshapiro } 286664562Sgshapiro } 286764562Sgshapiro else 286864562Sgshapiro { 286990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287090792Sgshapiro macid("{if_name_out}"), NULL); 287190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287290792Sgshapiro macid("{if_addr_out}"), NULL); 287390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287490792Sgshapiro macid("{if_family_out}"), NULL); 287564562Sgshapiro } 2876132943Sgshapiro 2877132943Sgshapiro /* Use the configured HeloName as appropriate */ 2878132943Sgshapiro if (HeloName != NULL && HeloName[0] != '\0') 2879223067Sgshapiro { 2880223067Sgshapiro SM_FREE_CLR(mci->mci_heloname); 2881132943Sgshapiro mci->mci_heloname = newstr(HeloName); 2882223067Sgshapiro } 2883132943Sgshapiro 288438032Speter mci_setstat(mci, EX_OK, NULL, NULL); 288564562Sgshapiro return EX_OK; 288638032Speter} 288764562Sgshapiro 288864562Sgshapirostatic void 2889141858Sgshapiroconnecttimeout(ignore) 2890141858Sgshapiro int ignore; 289164562Sgshapiro{ 289277349Sgshapiro /* 289377349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 289477349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 289577349Sgshapiro ** DOING. 289677349Sgshapiro */ 289777349Sgshapiro 289864562Sgshapiro errno = ETIMEDOUT; 289964562Sgshapiro longjmp(CtxConnectTimeout, 1); 290064562Sgshapiro} 290190792Sgshapiro/* 290264562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 290364562Sgshapiro** 290464562Sgshapiro** Parameters: 290564562Sgshapiro** mux_path -- the path of the socket to connect to. 290664562Sgshapiro** mci -- a pointer to the mail connection information 290764562Sgshapiro** structure to be filled in. 290864562Sgshapiro** 290964562Sgshapiro** Returns: 291064562Sgshapiro** An exit code telling whether the connection could be 291164562Sgshapiro** made and if not why not. 291264562Sgshapiro** 291364562Sgshapiro** Side Effects: 291464562Sgshapiro** none. 291564562Sgshapiro*/ 291664562Sgshapiro 291790792Sgshapiro#if NETUNIX 291890792Sgshapiroint 291990792Sgshapiromakeconnection_ds(mux_path, mci) 292064562Sgshapiro char *mux_path; 292164562Sgshapiro register MCI *mci; 292264562Sgshapiro{ 292364562Sgshapiro int sock; 292464562Sgshapiro int rval, save_errno; 292564562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 292664562Sgshapiro struct sockaddr_un unix_addr; 292764562Sgshapiro 292864562Sgshapiro /* if not safe, don't connect */ 292964562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 293064562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 293164562Sgshapiro 293264562Sgshapiro if (rval != 0) 293364562Sgshapiro { 2934132943Sgshapiro syserr("makeconnection_ds: unsafe domain socket %s", 2935132943Sgshapiro mux_path); 293664562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 293764562Sgshapiro errno = rval; 293864562Sgshapiro return EX_TEMPFAIL; 293964562Sgshapiro } 294064562Sgshapiro 294164562Sgshapiro /* prepare address structure */ 2942168515Sgshapiro memset(&unix_addr, '\0', sizeof(unix_addr)); 294364562Sgshapiro unix_addr.sun_family = AF_UNIX; 294464562Sgshapiro 2945168515Sgshapiro if (strlen(mux_path) >= sizeof(unix_addr.sun_path)) 294664562Sgshapiro { 2947132943Sgshapiro syserr("makeconnection_ds: domain socket name %s too long", 2948132943Sgshapiro mux_path); 294990792Sgshapiro 295090792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 295164562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 295264562Sgshapiro errno = ENAMETOOLONG; 295364562Sgshapiro return EX_UNAVAILABLE; 295464562Sgshapiro } 295590792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 2956168515Sgshapiro sizeof(unix_addr.sun_path)); 295764562Sgshapiro 295864562Sgshapiro /* initialize domain socket */ 295964562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 296064562Sgshapiro if (sock == -1) 296164562Sgshapiro { 296264562Sgshapiro save_errno = errno; 2963132943Sgshapiro syserr("makeconnection_ds: could not create domain socket %s", 2964132943Sgshapiro mux_path); 296564562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 296664562Sgshapiro errno = save_errno; 296764562Sgshapiro return EX_TEMPFAIL; 296864562Sgshapiro } 296964562Sgshapiro 297064562Sgshapiro /* connect to server */ 297164562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 297264562Sgshapiro sizeof(unix_addr)) == -1) 297364562Sgshapiro { 297464562Sgshapiro save_errno = errno; 297564562Sgshapiro syserr("Could not connect to socket %s", mux_path); 297664562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 297764562Sgshapiro (void) close(sock); 297864562Sgshapiro errno = save_errno; 297964562Sgshapiro return EX_TEMPFAIL; 298064562Sgshapiro } 298164562Sgshapiro 298264562Sgshapiro /* connection ok, put it into canonical form */ 298364562Sgshapiro mci->mci_out = NULL; 298490792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2985132943Sgshapiro (void *) &sock, SM_IO_WRONLY_B, NULL)) 298690792Sgshapiro == NULL 298790792Sgshapiro || (sock = dup(sock)) < 0 || 298890792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2989132943Sgshapiro (void *) &sock, SM_IO_RDONLY_B, NULL)) 299090792Sgshapiro == NULL) 299164562Sgshapiro { 299264562Sgshapiro save_errno = errno; 299364562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 299464562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 299564562Sgshapiro if (mci->mci_out != NULL) 299690792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 299764562Sgshapiro (void) close(sock); 299864562Sgshapiro errno = save_errno; 299964562Sgshapiro return EX_TEMPFAIL; 300064562Sgshapiro } 300190792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 300264562Sgshapiro 300364562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 300464562Sgshapiro errno = 0; 300564562Sgshapiro return EX_OK; 300664562Sgshapiro} 300790792Sgshapiro#endif /* NETUNIX */ 300890792Sgshapiro/* 300990792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 301077349Sgshapiro** 301177349Sgshapiro** Parameters: 301290792Sgshapiro** none. 301377349Sgshapiro** 301477349Sgshapiro** Returns: 301577349Sgshapiro** none. 301677349Sgshapiro** 301777349Sgshapiro** Side Effects: 301890792Sgshapiro** closes control socket, exits. 301977349Sgshapiro*/ 302077349Sgshapiro 302190792Sgshapirovoid 302290792Sgshapiroshutdown_daemon() 302377349Sgshapiro{ 302490792Sgshapiro int i; 302590792Sgshapiro char *reason; 302677349Sgshapiro 302790792Sgshapiro sm_allsignals(true); 302890792Sgshapiro 302990792Sgshapiro reason = ShutdownRequest; 303090792Sgshapiro ShutdownRequest = NULL; 303190792Sgshapiro PendingSignal = 0; 303290792Sgshapiro 3033132943Sgshapiro if (LogLevel > 9) 3034132943Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s", 303590792Sgshapiro reason == NULL ? "implicit call" : reason); 303690792Sgshapiro 303790792Sgshapiro FileName = NULL; 303890792Sgshapiro closecontrolsocket(true); 303990792Sgshapiro#if XLA 304090792Sgshapiro xla_all_end(); 304190792Sgshapiro#endif /* XLA */ 304290792Sgshapiro 304390792Sgshapiro for (i = 0; i < NDaemons; i++) 304490792Sgshapiro { 304590792Sgshapiro if (Daemons[i].d_socket >= 0) 304690792Sgshapiro { 304790792Sgshapiro (void) close(Daemons[i].d_socket); 304890792Sgshapiro Daemons[i].d_socket = -1; 304990792Sgshapiro 305090792Sgshapiro#if _FFR_DAEMON_NETUNIX 305190792Sgshapiro# if NETUNIX 305290792Sgshapiro /* Remove named sockets */ 305390792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 305490792Sgshapiro { 305590792Sgshapiro int rval; 305690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 305790792Sgshapiro 305890792Sgshapiro /* if not safe, don't use it */ 305990792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 306090792Sgshapiro RunAsUid, RunAsGid, 306190792Sgshapiro RunAsUserName, sff, 306290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 306390792Sgshapiro if (rval == 0 && 306490792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 306590792Sgshapiro { 306690792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 306790792Sgshapiro "Could not remove daemon %s socket: %s: %s", 306890792Sgshapiro Daemons[i].d_name, 306990792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 307090792Sgshapiro sm_errstring(errno)); 307190792Sgshapiro } 307290792Sgshapiro } 307390792Sgshapiro# endif /* NETUNIX */ 307490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 307590792Sgshapiro } 307690792Sgshapiro } 307790792Sgshapiro 307890792Sgshapiro finis(false, true, EX_OK); 307977349Sgshapiro} 308090792Sgshapiro/* 308177349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 308277349Sgshapiro** 308377349Sgshapiro** Parameters: 308477349Sgshapiro** none. 308577349Sgshapiro** 308677349Sgshapiro** Returns: 308777349Sgshapiro** none. 308877349Sgshapiro** 308977349Sgshapiro** Side Effects: 309077349Sgshapiro** restarts the daemon or exits if restart fails. 309177349Sgshapiro*/ 309277349Sgshapiro 309380785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 309480785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 309580785Sgshapirodo \ 309680785Sgshapiro{ \ 309790792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 309880785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 309990792Sgshapiro (void) sm_signal((sig), (old)); \ 310080785Sgshapiro} while (0) 310180785Sgshapiro 310290792Sgshapirovoid 310377349Sgshapirorestart_daemon() 310477349Sgshapiro{ 310590792Sgshapiro bool drop; 310677349Sgshapiro int save_errno; 310777349Sgshapiro char *reason; 310880785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 310977349Sgshapiro extern int DtableSize; 311077349Sgshapiro 311180785Sgshapiro /* clear the events to turn off SIGALRMs */ 311290792Sgshapiro sm_clear_events(); 311390792Sgshapiro sm_allsignals(true); 311477349Sgshapiro 311577349Sgshapiro reason = RestartRequest; 311677349Sgshapiro RestartRequest = NULL; 311777349Sgshapiro PendingSignal = 0; 311877349Sgshapiro 311977349Sgshapiro if (SaveArgv[0][0] != '/') 312077349Sgshapiro { 312177349Sgshapiro if (LogLevel > 3) 312277349Sgshapiro sm_syslog(LOG_INFO, NOQID, 312377349Sgshapiro "could not restart: need full path"); 312490792Sgshapiro finis(false, true, EX_OSFILE); 312590792Sgshapiro /* NOTREACHED */ 312677349Sgshapiro } 312777349Sgshapiro if (LogLevel > 3) 312877349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 312977349Sgshapiro SaveArgv[0], 313077349Sgshapiro reason == NULL ? "implicit call" : reason); 313177349Sgshapiro 313290792Sgshapiro closecontrolsocket(true); 313398121Sgshapiro#if SM_CONF_SHM 313498121Sgshapiro cleanup_shm(DaemonPid == getpid()); 313598121Sgshapiro#endif /* SM_CONF_SHM */ 313690792Sgshapiro 3137132943Sgshapiro /* close locked pid file */ 3138132943Sgshapiro close_sendmail_pid(); 3139132943Sgshapiro 314090792Sgshapiro /* 314190792Sgshapiro ** Want to drop to the user who started the process in all cases 314290792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 314390792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 314490792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 314590792Sgshapiro */ 314690792Sgshapiro 314790792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 314890792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 314990792Sgshapiro 315090792Sgshapiro if (drop_privileges(drop) != EX_OK) 315177349Sgshapiro { 315277349Sgshapiro if (LogLevel > 0) 315377349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 315490792Sgshapiro "could not drop privileges: %s", 315590792Sgshapiro sm_errstring(errno)); 315690792Sgshapiro finis(false, true, EX_OSERR); 315790792Sgshapiro /* NOTREACHED */ 315877349Sgshapiro } 315977349Sgshapiro 3160132943Sgshapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 316177349Sgshapiro 316280785Sgshapiro /* 316380785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 316480785Sgshapiro ** However, the default action can be "terminate", so it isn't 316580785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 316680785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 316780785Sgshapiro */ 316880785Sgshapiro 316980785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 317080785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 317180785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 317280785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 317380785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 317480785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 317580785Sgshapiro#ifdef SIGUSR1 317680785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 317780785Sgshapiro#endif /* SIGUSR1 */ 317894334Sgshapiro 317994334Sgshapiro /* Turn back on signals */ 318090792Sgshapiro sm_allsignals(false); 318177349Sgshapiro 318277349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 318377349Sgshapiro save_errno = errno; 318477349Sgshapiro 318580785Sgshapiro /* block signals again and restore needed signals */ 318690792Sgshapiro sm_allsignals(true); 318780785Sgshapiro 318880785Sgshapiro /* For finis() events */ 318990792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 319080785Sgshapiro 319180785Sgshapiro#ifdef SIGUSR1 319280785Sgshapiro /* For debugging finis() */ 319390792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 319480785Sgshapiro#endif /* SIGUSR1 */ 319577349Sgshapiro 319677349Sgshapiro errno = save_errno; 319777349Sgshapiro if (LogLevel > 0) 319890792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 319990792Sgshapiro SaveArgv[0], sm_errstring(errno)); 320090792Sgshapiro finis(false, true, EX_OSFILE); 320190792Sgshapiro /* NOTREACHED */ 320277349Sgshapiro} 320390792Sgshapiro/* 320438032Speter** MYHOSTNAME -- return the name of this host. 320538032Speter** 320638032Speter** Parameters: 320738032Speter** hostbuf -- a place to return the name of this host. 320838032Speter** size -- the size of hostbuf. 320938032Speter** 321038032Speter** Returns: 321138032Speter** A list of aliases for this host. 321238032Speter** 321338032Speter** Side Effects: 321438032Speter** Adds numeric codes to $=w. 321538032Speter*/ 321638032Speter 321738032Speterstruct hostent * 321838032Spetermyhostname(hostbuf, size) 321938032Speter char hostbuf[]; 322038032Speter int size; 322138032Speter{ 322238032Speter register struct hostent *hp; 322338032Speter 322473188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 322590792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 322664562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 322790792Sgshapiro#if NETINET && NETINET6 322880785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 322980785Sgshapiro { 323080785Sgshapiro /* 323180785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 323280785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 323380785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 323480785Sgshapiro */ 323580785Sgshapiro 323680785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 323780785Sgshapiro } 323890792Sgshapiro#endif /* NETINET && NETINET6 */ 323938032Speter if (hp == NULL) 324038032Speter return NULL; 324138032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 324264562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 324364562Sgshapiro 324490792Sgshapiro#if NETINFO 324564562Sgshapiro if (strchr(hostbuf, '.') == NULL) 324638032Speter { 324764562Sgshapiro char *domainname; 324864562Sgshapiro 324964562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 325064562Sgshapiro "domain", '\0'); 325164562Sgshapiro if (domainname != NULL && 325264562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 325390792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 325438032Speter } 325590792Sgshapiro#endif /* NETINFO */ 325638032Speter 325738032Speter /* 325838032Speter ** If there is still no dot in the name, try looking for a 325938032Speter ** dotted alias. 326038032Speter */ 326138032Speter 326238032Speter if (strchr(hostbuf, '.') == NULL) 326338032Speter { 326438032Speter char **ha; 326538032Speter 326664562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 326738032Speter { 326838032Speter if (strchr(*ha, '.') != NULL) 326938032Speter { 327064562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 327138032Speter hostbuf[size - 1] = '\0'; 327238032Speter break; 327338032Speter } 327438032Speter } 327538032Speter } 327638032Speter 327738032Speter /* 327838032Speter ** If _still_ no dot, wait for a while and try again -- it is 327938032Speter ** possible that some service is starting up. This can result 328038032Speter ** in excessive delays if the system is badly configured, but 328138032Speter ** there really isn't a way around that, particularly given that 328238032Speter ** the config file hasn't been read at this point. 328338032Speter ** All in all, a bit of a mess. 328438032Speter */ 328538032Speter 328638032Speter if (strchr(hostbuf, '.') == NULL && 328790792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 328838032Speter { 3289182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_CRIT, NOQID, 329064562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 329164562Sgshapiro hostbuf); 329238032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 329338032Speter hostbuf); 329464562Sgshapiro (void) sleep(60); 329590792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 329638032Speter { 3297182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_ALERT, NOQID, 329864562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 329964562Sgshapiro hostbuf); 330038032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 330138032Speter hostbuf); 330238032Speter } 330338032Speter } 330464562Sgshapiro return hp; 330538032Speter} 330690792Sgshapiro/* 330738032Speter** ADDRCMP -- compare two host addresses 330838032Speter** 330938032Speter** Parameters: 331038032Speter** hp -- hostent structure for the first address 331138032Speter** ha -- actual first address 331238032Speter** sa -- second address 331338032Speter** 331438032Speter** Returns: 331538032Speter** 0 -- if ha and sa match 331638032Speter** else -- they don't match 331738032Speter*/ 331838032Speter 331964562Sgshapirostatic int 332038032Speteraddrcmp(hp, ha, sa) 332138032Speter struct hostent *hp; 332238032Speter char *ha; 332338032Speter SOCKADDR *sa; 332438032Speter{ 332590792Sgshapiro#if NETINET6 332690792Sgshapiro unsigned char *a; 332790792Sgshapiro#endif /* NETINET6 */ 332864562Sgshapiro 332938032Speter switch (sa->sa.sa_family) 333038032Speter { 333190792Sgshapiro#if NETINET 333238032Speter case AF_INET: 333338032Speter if (hp->h_addrtype == AF_INET) 333464562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 333538032Speter break; 333690792Sgshapiro#endif /* NETINET */ 333738032Speter 333890792Sgshapiro#if NETINET6 333964562Sgshapiro case AF_INET6: 334090792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 334164562Sgshapiro 334264562Sgshapiro /* Straight binary comparison */ 334364562Sgshapiro if (hp->h_addrtype == AF_INET6) 334464562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 334564562Sgshapiro 334664562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 334764562Sgshapiro if (hp->h_addrtype == AF_INET && 334864562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 334964562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 335064562Sgshapiro break; 335190792Sgshapiro#endif /* NETINET6 */ 335238032Speter } 335338032Speter return -1; 335438032Speter} 335590792Sgshapiro/* 335664562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 335738032Speter** 335838032Speter** Uses RFC1413 protocol to try to get info from the other end. 335938032Speter** 336038032Speter** Parameters: 336138032Speter** fd -- the descriptor 336290792Sgshapiro** may_be_forged -- an outage that is set to true if the 336338032Speter** forward lookup of RealHostName does not match 336490792Sgshapiro** RealHostAddr; set to false if they do match. 336538032Speter** 336638032Speter** Returns: 336738032Speter** The user@host information associated with this descriptor. 336838032Speter*/ 336938032Speter 337038032Speterstatic jmp_buf CtxAuthTimeout; 337138032Speter 337238032Speterstatic void 3373141858Sgshapiroauthtimeout(ignore) 3374141858Sgshapiro int ignore; 337538032Speter{ 337677349Sgshapiro /* 337777349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 337877349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 337977349Sgshapiro ** DOING. 338077349Sgshapiro */ 338177349Sgshapiro 338277349Sgshapiro errno = ETIMEDOUT; 338338032Speter longjmp(CtxAuthTimeout, 1); 338438032Speter} 338538032Speter 338638032Speterchar * 338738032Spetergetauthinfo(fd, may_be_forged) 338838032Speter int fd; 338938032Speter bool *may_be_forged; 339038032Speter{ 339190792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 339238032Speter SOCKADDR_LEN_T falen; 339338032Speter register char *volatile p = NULL; 339438032Speter SOCKADDR la; 339538032Speter SOCKADDR_LEN_T lalen; 339690792Sgshapiro#ifndef NO_GETSERVBYNAME 339738032Speter register struct servent *sp; 339890792Sgshapiro# if NETINET 339990792Sgshapiro static unsigned short port4 = 0; 340090792Sgshapiro# endif /* NETINET */ 340190792Sgshapiro# if NETINET6 340290792Sgshapiro static unsigned short port6 = 0; 340390792Sgshapiro# endif /* NETINET6 */ 340490792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 340538032Speter volatile int s; 340638032Speter int i = 0; 340790792Sgshapiro size_t len; 340890792Sgshapiro SM_EVENT *ev; 340938032Speter int nleft; 341038032Speter struct hostent *hp; 341138032Speter char *ostype = NULL; 341238032Speter char **ha; 341338032Speter char ibuf[MAXNAME + 1]; 3414110560Sgshapiro static char hbuf[MAXNAME + MAXAUTHINFO + 11]; 341538032Speter 341690792Sgshapiro *may_be_forged = false; 3417168515Sgshapiro falen = sizeof(RealHostAddr); 341838032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 341938032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 342038032Speter { 342164562Sgshapiro if (i < 0) 342264562Sgshapiro { 342364562Sgshapiro /* 342464562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 342564562Sgshapiro ** errno in this case, so a mis-report doesn't 342664562Sgshapiro ** happen later. 342764562Sgshapiro */ 342890792Sgshapiro 342964562Sgshapiro if (errno != ENOTSOCK) 343064562Sgshapiro return NULL; 343164562Sgshapiro errno = 0; 343264562Sgshapiro } 3433168515Sgshapiro (void) sm_strlcpyn(hbuf, sizeof(hbuf), 2, RealUserName, 343490792Sgshapiro "@localhost"); 343538032Speter if (tTd(9, 1)) 343690792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 343738032Speter return hbuf; 343838032Speter } 343938032Speter 344038032Speter if (RealHostName == NULL) 344138032Speter { 344238032Speter /* translate that to a host name */ 344338032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 344438032Speter if (strlen(RealHostName) > MAXNAME) 344590792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 344638032Speter } 344738032Speter 344838032Speter /* cross check RealHostName with forward DNS lookup */ 344990792Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] != '[' && 345090792Sgshapiro RealHostName[0] != '[') 345138032Speter { 345280785Sgshapiro int family; 345380785Sgshapiro 345480785Sgshapiro family = RealHostAddr.sa.sa_family; 345590792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 345680785Sgshapiro /* 345780785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 345880785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 345980785Sgshapiro ** address(es) for addrcmp() to compare against 346080785Sgshapiro ** RealHostAddr. 346180785Sgshapiro ** 346280785Sgshapiro ** Actually, we only need to do this for systems 346380785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 346480785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 346580785Sgshapiro ** flag. A better fix to this problem is to add this 346680785Sgshapiro ** functionality to our stub getipnodebyname(). 346780785Sgshapiro */ 346880785Sgshapiro 346980785Sgshapiro if (family == AF_INET6 && 347080785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 347180785Sgshapiro family = AF_INET; 347290792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 347380785Sgshapiro 347438032Speter /* try to match the reverse against the forward lookup */ 347580785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 347638032Speter if (hp == NULL) 3477120256Sgshapiro { 3478132943Sgshapiro /* XXX: Could be a temporary error on forward lookup */ 347990792Sgshapiro *may_be_forged = true; 3480120256Sgshapiro } 348138032Speter else 348238032Speter { 348338032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 348490792Sgshapiro { 348538032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 348638032Speter break; 348790792Sgshapiro } 348838032Speter *may_be_forged = *ha == NULL; 348990792Sgshapiro#if NETINET6 349071345Sgshapiro freehostent(hp); 349171345Sgshapiro hp = NULL; 349290792Sgshapiro#endif /* NETINET6 */ 349338032Speter } 349438032Speter } 349538032Speter 349638032Speter if (TimeOuts.to_ident == 0) 349738032Speter goto noident; 349838032Speter 3499168515Sgshapiro lalen = sizeof(la); 350064562Sgshapiro switch (RealHostAddr.sa.sa_family) 350138032Speter { 350290792Sgshapiro#if NETINET 350364562Sgshapiro case AF_INET: 350464562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 350564562Sgshapiro lalen <= 0 || 350664562Sgshapiro la.sa.sa_family != AF_INET) 350764562Sgshapiro { 350864562Sgshapiro /* no ident info */ 350964562Sgshapiro goto noident; 351064562Sgshapiro } 351164562Sgshapiro port = RealHostAddr.sin.sin_port; 351238032Speter 351364562Sgshapiro /* create ident query */ 3514168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 351564562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 351664562Sgshapiro ntohs(la.sin.sin_port)); 351738032Speter 351864562Sgshapiro /* create local address */ 351964562Sgshapiro la.sin.sin_port = 0; 352038032Speter 352164562Sgshapiro /* create foreign address */ 352290792Sgshapiro# ifdef NO_GETSERVBYNAME 352338032Speter RealHostAddr.sin.sin_port = htons(113); 352490792Sgshapiro# else /* NO_GETSERVBYNAME */ 352590792Sgshapiro 352690792Sgshapiro /* 352790792Sgshapiro ** getservbyname() consumes about 5% of the time 352890792Sgshapiro ** when receiving a small message (almost all of the time 352990792Sgshapiro ** spent in this routine). 353090792Sgshapiro ** Hence we store the port in a static variable 353190792Sgshapiro ** to save this time. 353290792Sgshapiro ** The portnumber shouldn't change very often... 353390792Sgshapiro ** This code makes the assumption that the port number 353490792Sgshapiro ** is not 0. 353590792Sgshapiro */ 353690792Sgshapiro 353790792Sgshapiro if (port4 == 0) 353890792Sgshapiro { 353990792Sgshapiro sp = getservbyname("auth", "tcp"); 354090792Sgshapiro if (sp != NULL) 354190792Sgshapiro port4 = sp->s_port; 354290792Sgshapiro else 354390792Sgshapiro port4 = htons(113); 354490792Sgshapiro } 354590792Sgshapiro RealHostAddr.sin.sin_port = port4; 354664562Sgshapiro break; 354790792Sgshapiro# endif /* NO_GETSERVBYNAME */ 354890792Sgshapiro#endif /* NETINET */ 354938032Speter 355090792Sgshapiro#if NETINET6 355164562Sgshapiro case AF_INET6: 355264562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 355364562Sgshapiro lalen <= 0 || 355464562Sgshapiro la.sa.sa_family != AF_INET6) 355564562Sgshapiro { 355664562Sgshapiro /* no ident info */ 355764562Sgshapiro goto noident; 355864562Sgshapiro } 355964562Sgshapiro port = RealHostAddr.sin6.sin6_port; 356064562Sgshapiro 356164562Sgshapiro /* create ident query */ 3562168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 356364562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 356464562Sgshapiro ntohs(la.sin6.sin6_port)); 356564562Sgshapiro 356664562Sgshapiro /* create local address */ 356764562Sgshapiro la.sin6.sin6_port = 0; 356864562Sgshapiro 356964562Sgshapiro /* create foreign address */ 357090792Sgshapiro# ifdef NO_GETSERVBYNAME 357164562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 357290792Sgshapiro# else /* NO_GETSERVBYNAME */ 357390792Sgshapiro if (port6 == 0) 357490792Sgshapiro { 357590792Sgshapiro sp = getservbyname("auth", "tcp"); 357690792Sgshapiro if (sp != NULL) 357790792Sgshapiro port6 = sp->s_port; 357890792Sgshapiro else 357990792Sgshapiro port6 = htons(113); 358090792Sgshapiro } 358190792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 358264562Sgshapiro break; 358390792Sgshapiro# endif /* NO_GETSERVBYNAME */ 358490792Sgshapiro#endif /* NETINET6 */ 358564562Sgshapiro default: 358664562Sgshapiro /* no ident info */ 358764562Sgshapiro goto noident; 358864562Sgshapiro } 358964562Sgshapiro 359038032Speter s = -1; 359138032Speter if (setjmp(CtxAuthTimeout) != 0) 359238032Speter { 359338032Speter if (s >= 0) 359438032Speter (void) close(s); 359538032Speter goto noident; 359638032Speter } 359738032Speter 359838032Speter /* put a timeout around the whole thing */ 359990792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 360038032Speter 360138032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 360264562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 360338032Speter if (s < 0) 360438032Speter { 360590792Sgshapiro sm_clrevent(ev); 360638032Speter goto noident; 360738032Speter } 360864562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 360964562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 361038032Speter goto closeident; 361138032Speter 361238032Speter if (tTd(9, 10)) 361390792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 361438032Speter 361538032Speter /* send query */ 361638032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 361738032Speter goto closeident; 361838032Speter 361938032Speter /* get result */ 362038032Speter p = &ibuf[0]; 3621168515Sgshapiro nleft = sizeof(ibuf) - 1; 362238032Speter while ((i = read(s, p, nleft)) > 0) 362338032Speter { 3624125820Sgshapiro char *s; 3625125820Sgshapiro 362638032Speter p += i; 362738032Speter nleft -= i; 362838032Speter *p = '\0'; 3629125820Sgshapiro if ((s = strchr(ibuf, '\n')) != NULL) 3630125820Sgshapiro { 3631125820Sgshapiro if (p > s + 1) 3632125820Sgshapiro { 3633125820Sgshapiro p = s + 1; 3634125820Sgshapiro *p = '\0'; 3635125820Sgshapiro } 363638032Speter break; 3637125820Sgshapiro } 3638125820Sgshapiro if (nleft <= 0) 3639125820Sgshapiro break; 364038032Speter } 364138032Speter (void) close(s); 364290792Sgshapiro sm_clrevent(ev); 364338032Speter if (i < 0 || p == &ibuf[0]) 364438032Speter goto noident; 364538032Speter 3646111823Sgshapiro if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r') 364738032Speter p--; 364838032Speter *++p = '\0'; 364938032Speter 365038032Speter if (tTd(9, 3)) 365190792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 365238032Speter 365338032Speter /* parse result */ 365438032Speter p = strchr(ibuf, ':'); 365538032Speter if (p == NULL) 365638032Speter { 365738032Speter /* malformed response */ 365838032Speter goto noident; 365938032Speter } 366038032Speter while (isascii(*++p) && isspace(*p)) 366138032Speter continue; 366290792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 366338032Speter { 366438032Speter /* presumably an error string */ 366538032Speter goto noident; 366638032Speter } 366738032Speter p += 6; 366838032Speter while (isascii(*p) && isspace(*p)) 366938032Speter p++; 367038032Speter if (*p++ != ':') 367138032Speter { 367238032Speter /* either useridxx or malformed response */ 367338032Speter goto noident; 367438032Speter } 367538032Speter 367638032Speter /* p now points to the OSTYPE field */ 367738032Speter while (isascii(*p) && isspace(*p)) 367838032Speter p++; 367938032Speter ostype = p; 368038032Speter p = strchr(p, ':'); 368138032Speter if (p == NULL) 368238032Speter { 368338032Speter /* malformed response */ 368438032Speter goto noident; 368538032Speter } 368638032Speter else 368738032Speter { 368838032Speter char *charset; 368938032Speter 369038032Speter *p = '\0'; 369138032Speter charset = strchr(ostype, ','); 369238032Speter if (charset != NULL) 369338032Speter *charset = '\0'; 369438032Speter } 369538032Speter 369638032Speter /* 1413 says don't do this -- but it's broken otherwise */ 369738032Speter while (isascii(*++p) && isspace(*p)) 369838032Speter continue; 369938032Speter 370038032Speter /* p now points to the authenticated name -- copy carefully */ 370190792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 370238032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 370338032Speter { 3704168515Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof(hbuf)); 3705110560Sgshapiro cleanstrcpy(&hbuf[6], p, MAXAUTHINFO); 370638032Speter } 370738032Speter else 3708110560Sgshapiro cleanstrcpy(hbuf, p, MAXAUTHINFO); 370990792Sgshapiro len = strlen(hbuf); 3710168515Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof(hbuf) - len, 2, "@", 371190792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 371238032Speter goto postident; 371338032Speter 371438032Spetercloseident: 371538032Speter (void) close(s); 371690792Sgshapiro sm_clrevent(ev); 371738032Speter 371838032Speternoident: 371964562Sgshapiro /* put back the original incoming port */ 372064562Sgshapiro switch (RealHostAddr.sa.sa_family) 372164562Sgshapiro { 372290792Sgshapiro#if NETINET 372364562Sgshapiro case AF_INET: 372464562Sgshapiro if (port > 0) 372564562Sgshapiro RealHostAddr.sin.sin_port = port; 372664562Sgshapiro break; 372790792Sgshapiro#endif /* NETINET */ 372864562Sgshapiro 372990792Sgshapiro#if NETINET6 373064562Sgshapiro case AF_INET6: 373164562Sgshapiro if (port > 0) 373264562Sgshapiro RealHostAddr.sin6.sin6_port = port; 373364562Sgshapiro break; 373490792Sgshapiro#endif /* NETINET6 */ 373564562Sgshapiro } 373664562Sgshapiro 373738032Speter if (RealHostName == NULL) 373838032Speter { 373938032Speter if (tTd(9, 1)) 374090792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 374138032Speter return NULL; 374238032Speter } 3743168515Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof(hbuf)); 374438032Speter 374538032Speterpostident: 374690792Sgshapiro#if IP_SRCROUTE 374790792Sgshapiro# ifndef GET_IPOPT_DST 374890792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 374990792Sgshapiro# endif /* ! GET_IPOPT_DST */ 375038032Speter /* 375138032Speter ** Extract IP source routing information. 375238032Speter ** 375338032Speter ** Format of output for a connection from site a through b 375438032Speter ** through c to d: 375538032Speter ** loose: @site-c@site-b:site-a 375638032Speter ** strict: !@site-c@site-b:site-a 375738032Speter ** 375838032Speter ** o - pointer within ipopt_list structure. 375938032Speter ** q - pointer within ls/ss rr route data 376038032Speter ** p - pointer to hbuf 376138032Speter */ 376238032Speter 376338032Speter if (RealHostAddr.sa.sa_family == AF_INET) 376438032Speter { 376538032Speter SOCKOPT_LEN_T ipoptlen; 376638032Speter int j; 376790792Sgshapiro unsigned char *q; 376890792Sgshapiro unsigned char *o; 376938032Speter int l; 377064562Sgshapiro struct IPOPTION ipopt; 377138032Speter 3772168515Sgshapiro ipoptlen = sizeof(ipopt); 377338032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 377438032Speter (char *) &ipopt, &ipoptlen) < 0) 377538032Speter goto noipsr; 377638032Speter if (ipoptlen == 0) 377738032Speter goto noipsr; 377890792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 377990792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 378038032Speter { 378138032Speter switch (*o) 378238032Speter { 378364562Sgshapiro case IPOPT_EOL: 378438032Speter o = NULL; 378538032Speter break; 378638032Speter 378738032Speter case IPOPT_NOP: 378838032Speter o++; 378938032Speter break; 379038032Speter 379138032Speter case IPOPT_SSRR: 379238032Speter case IPOPT_LSRR: 379338032Speter /* 379438032Speter ** Source routing. 379538032Speter ** o[0] is the option type (loose/strict). 379638032Speter ** o[1] is the length of this option, 379738032Speter ** including option type and 379838032Speter ** length. 379938032Speter ** o[2] is the pointer into the route 380038032Speter ** data. 380138032Speter ** o[3] begins the route data. 380238032Speter */ 380338032Speter 380438032Speter p = &hbuf[strlen(hbuf)]; 3805168515Sgshapiro l = sizeof(hbuf) - (hbuf - p) - 6; 380690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 380790792Sgshapiro " [%s@%.*s", 380890792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 380990792Sgshapiro l > 240 ? 120 : l / 2, 381090792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 381138032Speter i = strlen(p); 381238032Speter p += i; 381338032Speter l -= strlen(p); 381438032Speter 381538032Speter j = o[1] / sizeof(struct in_addr) - 1; 381638032Speter 381738032Speter /* q skips length and router pointer to data */ 381838032Speter q = &o[3]; 381938032Speter for ( ; j >= 0; j--) 382038032Speter { 382164562Sgshapiro struct in_addr addr; 382264562Sgshapiro 382338032Speter memcpy(&addr, q, sizeof(addr)); 382490792Sgshapiro (void) sm_snprintf(p, 382590792Sgshapiro SPACELEFT(hbuf, p), 382690792Sgshapiro "%c%.*s", 382790792Sgshapiro j != 0 ? '@' : ':', 382890792Sgshapiro l > 240 ? 120 : 382990792Sgshapiro j == 0 ? l : l / 2, 383090792Sgshapiro inet_ntoa(addr)); 383138032Speter i = strlen(p); 383238032Speter p += i; 383338032Speter l -= i + 1; 383464562Sgshapiro q += sizeof(struct in_addr); 383538032Speter } 383638032Speter o += o[1]; 383738032Speter break; 383838032Speter 383938032Speter default: 384038032Speter /* Skip over option */ 384138032Speter o += o[1]; 384238032Speter break; 384338032Speter } 384438032Speter } 384590792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 384638032Speter goto postipsr; 384738032Speter } 384838032Speter 384938032Speternoipsr: 385090792Sgshapiro#endif /* IP_SRCROUTE */ 385138032Speter if (RealHostName != NULL && RealHostName[0] != '[') 385238032Speter { 385338032Speter p = &hbuf[strlen(hbuf)]; 385490792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 385590792Sgshapiro anynet_ntoa(&RealHostAddr)); 385638032Speter } 385738032Speter if (*may_be_forged) 385838032Speter { 385938032Speter p = &hbuf[strlen(hbuf)]; 386090792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 386190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 386290792Sgshapiro macid("{client_resolve}"), "FORGED"); 386338032Speter } 386438032Speter 386590792Sgshapiro#if IP_SRCROUTE 386638032Speterpostipsr: 386790792Sgshapiro#endif /* IP_SRCROUTE */ 386864562Sgshapiro 386964562Sgshapiro /* put back the original incoming port */ 387064562Sgshapiro switch (RealHostAddr.sa.sa_family) 387164562Sgshapiro { 387290792Sgshapiro#if NETINET 387364562Sgshapiro case AF_INET: 387464562Sgshapiro if (port > 0) 387564562Sgshapiro RealHostAddr.sin.sin_port = port; 387664562Sgshapiro break; 387790792Sgshapiro#endif /* NETINET */ 387864562Sgshapiro 387990792Sgshapiro#if NETINET6 388064562Sgshapiro case AF_INET6: 388164562Sgshapiro if (port > 0) 388264562Sgshapiro RealHostAddr.sin6.sin6_port = port; 388364562Sgshapiro break; 388490792Sgshapiro#endif /* NETINET6 */ 388564562Sgshapiro } 388664562Sgshapiro 388790792Sgshapiro if (tTd(9, 1)) 388890792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 388938032Speter return hbuf; 389038032Speter} 389190792Sgshapiro/* 389238032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 389338032Speter** 389438032Speter** Parameters: 389538032Speter** map -- a pointer to this map. 389638032Speter** name -- the (presumably unqualified) hostname. 389738032Speter** av -- unused -- for compatibility with other mapping 389838032Speter** functions. 389938032Speter** statp -- an exit status (out parameter) -- set to 390038032Speter** EX_TEMPFAIL if the name server is unavailable. 390138032Speter** 390238032Speter** Returns: 390338032Speter** The mapping, if found. 390438032Speter** NULL if no mapping found. 390538032Speter** 390638032Speter** Side Effects: 390738032Speter** Looks up the host specified in hbuf. If it is not 390838032Speter** the canonical name for that host, return the canonical 390938032Speter** name (unless MF_MATCHONLY is set, which will cause the 391038032Speter** status only to be returned). 391138032Speter*/ 391238032Speter 391338032Speterchar * 391438032Speterhost_map_lookup(map, name, av, statp) 391538032Speter MAP *map; 391638032Speter char *name; 391738032Speter char **av; 391838032Speter int *statp; 391938032Speter{ 392038032Speter register struct hostent *hp; 392190792Sgshapiro#if NETINET 392238032Speter struct in_addr in_addr; 392390792Sgshapiro#endif /* NETINET */ 392490792Sgshapiro#if NETINET6 392564562Sgshapiro struct in6_addr in6_addr; 392690792Sgshapiro#endif /* NETINET6 */ 392764562Sgshapiro char *cp, *ans = NULL; 392838032Speter register STAB *s; 392990792Sgshapiro time_t now; 393090792Sgshapiro#if NAMED_BIND 393190792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 393290792Sgshapiro int SM_NONVOLATILE retry = 0; 393390792Sgshapiro#endif /* NAMED_BIND */ 393438032Speter char hbuf[MAXNAME + 1]; 393538032Speter 393638032Speter /* 393738032Speter ** See if we have already looked up this name. If so, just 393890792Sgshapiro ** return it (unless expired). 393938032Speter */ 394038032Speter 394190792Sgshapiro now = curtime(); 394238032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 394390792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 394490792Sgshapiro s->s_namecanon.nc_exp >= now) 394538032Speter { 394638032Speter if (tTd(9, 1)) 394790792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 394890792Sgshapiro name, 394990792Sgshapiro s->s_namecanon.nc_cname == NULL 395038032Speter ? "NULL" 395138032Speter : s->s_namecanon.nc_cname); 395238032Speter errno = s->s_namecanon.nc_errno; 395373188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 395438032Speter *statp = s->s_namecanon.nc_stat; 395538032Speter if (*statp == EX_TEMPFAIL) 395638032Speter { 395738032Speter CurEnv->e_status = "4.4.3"; 395838032Speter message("851 %s: Name server timeout", 395938032Speter shortenstring(name, 33)); 396038032Speter } 396138032Speter if (*statp != EX_OK) 396238032Speter return NULL; 396338032Speter if (s->s_namecanon.nc_cname == NULL) 396438032Speter { 3965132943Sgshapiro syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d", 396664562Sgshapiro name, 396764562Sgshapiro s->s_namecanon.nc_errno, 396864562Sgshapiro s->s_namecanon.nc_herrno); 396938032Speter return NULL; 397038032Speter } 397138032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 397238032Speter cp = map_rewrite(map, name, strlen(name), NULL); 397338032Speter else 397438032Speter cp = map_rewrite(map, 397538032Speter s->s_namecanon.nc_cname, 397638032Speter strlen(s->s_namecanon.nc_cname), 397738032Speter av); 397838032Speter return cp; 397938032Speter } 398038032Speter 398138032Speter /* 398238032Speter ** If we are running without a regular network connection (usually 398338032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 398438032Speter ** lookups because those could try to connect to a server. 398538032Speter */ 398638032Speter 398764562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 398864562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 398938032Speter { 399038032Speter if (tTd(9, 1)) 399190792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 399238032Speter *statp = EX_TEMPFAIL; 399338032Speter return NULL; 399438032Speter } 399538032Speter 399638032Speter /* 399738032Speter ** If first character is a bracket, then it is an address 399838032Speter ** lookup. Address is copied into a temporary buffer to 399938032Speter ** strip the brackets and to preserve name if address is 400038032Speter ** unknown. 400138032Speter */ 400238032Speter 400364562Sgshapiro if (tTd(9, 1)) 400490792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 400590792Sgshapiro#if NAMED_BIND 400690792Sgshapiro if (map->map_timeout > 0) 400790792Sgshapiro { 400890792Sgshapiro retrans = _res.retrans; 400990792Sgshapiro _res.retrans = map->map_timeout; 401090792Sgshapiro } 401190792Sgshapiro if (map->map_retry > 0) 401290792Sgshapiro { 401390792Sgshapiro retry = _res.retry; 401490792Sgshapiro _res.retry = map->map_retry; 401590792Sgshapiro } 401690792Sgshapiro#endif /* NAMED_BIND */ 401790792Sgshapiro 401890792Sgshapiro /* set default TTL */ 401990792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 402038032Speter if (*name != '[') 402138032Speter { 402290792Sgshapiro int ttl; 402390792Sgshapiro 4024168515Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof(hbuf)); 4025168515Sgshapiro if (getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl)) 402690792Sgshapiro { 402764562Sgshapiro ans = hbuf; 402890792Sgshapiro if (ttl > 0) 402990792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 403090792Sgshapiro SM_DEFAULT_TTL); 403190792Sgshapiro } 403264562Sgshapiro } 403364562Sgshapiro else 403464562Sgshapiro { 403564562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 403671345Sgshapiro { 403771345Sgshapiro if (tTd(9, 1)) 403890792Sgshapiro sm_dprintf("FAILED\n"); 403964562Sgshapiro return NULL; 404071345Sgshapiro } 404164562Sgshapiro *cp = '\0'; 404264562Sgshapiro 404364562Sgshapiro hp = NULL; 404490792Sgshapiro#if NETINET 404564562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 404664562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 404764562Sgshapiro INADDRSZ, AF_INET); 404890792Sgshapiro#endif /* NETINET */ 404990792Sgshapiro#if NETINET6 405064562Sgshapiro if (hp == NULL && 405190792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 405264562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 405364562Sgshapiro IN6ADDRSZ, AF_INET6); 405490792Sgshapiro#endif /* NETINET6 */ 405564562Sgshapiro *cp = ']'; 405664562Sgshapiro 405764562Sgshapiro if (hp != NULL) 405838032Speter { 405964562Sgshapiro /* found a match -- copy out */ 406090792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 406190792Sgshapiro#if NETINET6 406290792Sgshapiro if (ans == hp->h_name) 406390792Sgshapiro { 406490792Sgshapiro static char n[MAXNAME + 1]; 406590792Sgshapiro 406690792Sgshapiro /* hp->h_name is about to disappear */ 4067168515Sgshapiro (void) sm_strlcpy(n, ans, sizeof(n)); 406890792Sgshapiro ans = n; 406990792Sgshapiro } 407071345Sgshapiro freehostent(hp); 407171345Sgshapiro hp = NULL; 407290792Sgshapiro#endif /* NETINET6 */ 407338032Speter } 407464562Sgshapiro } 407590792Sgshapiro#if NAMED_BIND 407690792Sgshapiro if (map->map_timeout > 0) 407790792Sgshapiro _res.retrans = retrans; 407890792Sgshapiro if (map->map_retry > 0) 407990792Sgshapiro _res.retry = retry; 408090792Sgshapiro#endif /* NAMED_BIND */ 408138032Speter 408264562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 408338032Speter 408464562Sgshapiro /* Found an answer */ 408564562Sgshapiro if (ans != NULL) 408664562Sgshapiro { 408764562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 408890792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 408990792Sgshapiro sm_free(s->s_namecanon.nc_cname); 409090792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 409164562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 409264562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 409364562Sgshapiro else 409464562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 409571345Sgshapiro if (tTd(9, 1)) 409690792Sgshapiro sm_dprintf("FOUND %s\n", ans); 409764562Sgshapiro return cp; 409838032Speter } 409938032Speter 410064562Sgshapiro 410164562Sgshapiro /* No match found */ 410238032Speter s->s_namecanon.nc_errno = errno; 410390792Sgshapiro#if NAMED_BIND 410438032Speter s->s_namecanon.nc_herrno = h_errno; 410564562Sgshapiro if (tTd(9, 1)) 410690792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 410764562Sgshapiro switch (h_errno) 410838032Speter { 410964562Sgshapiro case TRY_AGAIN: 411064562Sgshapiro if (UseNameServer) 411164562Sgshapiro { 411264562Sgshapiro CurEnv->e_status = "4.4.3"; 411364562Sgshapiro message("851 %s: Name server timeout", 411464562Sgshapiro shortenstring(name, 33)); 411564562Sgshapiro } 411664562Sgshapiro *statp = EX_TEMPFAIL; 411764562Sgshapiro break; 411864562Sgshapiro 411964562Sgshapiro case HOST_NOT_FOUND: 412064562Sgshapiro case NO_DATA: 412164562Sgshapiro *statp = EX_NOHOST; 412264562Sgshapiro break; 412364562Sgshapiro 412464562Sgshapiro case NO_RECOVERY: 412564562Sgshapiro *statp = EX_SOFTWARE; 412664562Sgshapiro break; 412764562Sgshapiro 412864562Sgshapiro default: 412964562Sgshapiro *statp = EX_UNAVAILABLE; 413064562Sgshapiro break; 413138032Speter } 413290792Sgshapiro#else /* NAMED_BIND */ 413364562Sgshapiro if (tTd(9, 1)) 413490792Sgshapiro sm_dprintf("FAIL\n"); 413564562Sgshapiro *statp = EX_NOHOST; 413690792Sgshapiro#endif /* NAMED_BIND */ 413764562Sgshapiro s->s_namecanon.nc_stat = *statp; 413864562Sgshapiro return NULL; 413938032Speter} 414038032Speter/* 414190792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 414238032Speter** 414338032Speter** Parameters: 414490792Sgshapiro** map -- a pointer to this map. 414590792Sgshapiro** args -- argument string. 414638032Speter** 414738032Speter** Returns: 414890792Sgshapiro** true. 414938032Speter*/ 415038032Speter 415138032Speterbool 415238032Speterhost_map_init(map, args) 415338032Speter MAP *map; 415438032Speter char *args; 415538032Speter{ 415638032Speter register char *p = args; 415738032Speter 415838032Speter for (;;) 415938032Speter { 416038032Speter while (isascii(*p) && isspace(*p)) 416138032Speter p++; 416238032Speter if (*p != '-') 416338032Speter break; 416438032Speter switch (*++p) 416538032Speter { 416638032Speter case 'a': 416738032Speter map->map_app = ++p; 416838032Speter break; 416938032Speter 417038032Speter case 'T': 417138032Speter map->map_tapp = ++p; 417238032Speter break; 417338032Speter 417438032Speter case 'm': 417538032Speter map->map_mflags |= MF_MATCHONLY; 417638032Speter break; 417738032Speter 417838032Speter case 't': 417938032Speter map->map_mflags |= MF_NODEFER; 418038032Speter break; 418164562Sgshapiro 418264562Sgshapiro case 'S': /* only for consistency */ 418364562Sgshapiro map->map_spacesub = *++p; 418464562Sgshapiro break; 418564562Sgshapiro 418664562Sgshapiro case 'D': 418764562Sgshapiro map->map_mflags |= MF_DEFER; 418864562Sgshapiro break; 418990792Sgshapiro 419090792Sgshapiro case 'd': 419190792Sgshapiro { 419290792Sgshapiro char *h; 419390792Sgshapiro 419490792Sgshapiro while (isascii(*++p) && isspace(*p)) 419590792Sgshapiro continue; 419690792Sgshapiro h = strchr(p, ' '); 419790792Sgshapiro if (h != NULL) 419890792Sgshapiro *h = '\0'; 419990792Sgshapiro map->map_timeout = convtime(p, 's'); 420090792Sgshapiro if (h != NULL) 420190792Sgshapiro *h = ' '; 420290792Sgshapiro } 420390792Sgshapiro break; 420490792Sgshapiro 420590792Sgshapiro case 'r': 420690792Sgshapiro while (isascii(*++p) && isspace(*p)) 420790792Sgshapiro continue; 420890792Sgshapiro map->map_retry = atoi(p); 420990792Sgshapiro break; 421038032Speter } 421138032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 421238032Speter p++; 421338032Speter if (*p != '\0') 421438032Speter *p++ = '\0'; 421538032Speter } 421638032Speter if (map->map_app != NULL) 421738032Speter map->map_app = newstr(map->map_app); 421838032Speter if (map->map_tapp != NULL) 421938032Speter map->map_tapp = newstr(map->map_tapp); 422090792Sgshapiro return true; 422138032Speter} 422290792Sgshapiro 422364562Sgshapiro#if NETINET6 422464562Sgshapiro/* 422564562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 422664562Sgshapiro** 422764562Sgshapiro** Parameters: 422864562Sgshapiro** s6a -- a pointer to an in6_addr structure. 422964562Sgshapiro** dst -- buffer to store result in 423064562Sgshapiro** dst_len -- size of dst buffer 423164562Sgshapiro** 423264562Sgshapiro** Returns: 423364562Sgshapiro** A printable version of that structure. 423464562Sgshapiro*/ 423590792Sgshapiro 423664562Sgshapirochar * 423764562Sgshapiroanynet_ntop(s6a, dst, dst_len) 423864562Sgshapiro struct in6_addr *s6a; 423964562Sgshapiro char *dst; 424064562Sgshapiro size_t dst_len; 424164562Sgshapiro{ 424264562Sgshapiro register char *ap; 424364562Sgshapiro 424464562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 424564562Sgshapiro ap = (char *) inet_ntop(AF_INET, 424664562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 424764562Sgshapiro dst, dst_len); 424864562Sgshapiro else 424990792Sgshapiro { 425090792Sgshapiro char *d; 425190792Sgshapiro size_t sz; 425290792Sgshapiro 425390792Sgshapiro /* Save pointer to beginning of string */ 425490792Sgshapiro d = dst; 425590792Sgshapiro 425690792Sgshapiro /* Add IPv6: protocol tag */ 425790792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 425890792Sgshapiro if (sz >= dst_len) 425990792Sgshapiro return NULL; 426090792Sgshapiro dst += sz; 426190792Sgshapiro dst_len -= sz; 4262261370Sgshapiro# if _FFR_IPV6_FULL 4263261370Sgshapiro ap = sm_inet6_ntop(s6a, dst, dst_len); 4264261370Sgshapiro# else /* _FFR_IPV6_FULL */ 426564562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 4266261370Sgshapiro# endif /* _FFR_IPV6_FULL */ 426790792Sgshapiro 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; 4413244928Sgshapiro if (_res.retry == 0) 4414244928Sgshapiro _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