daemon.c revision 203004
138032Speter/* 2203004Sgshapiro * Copyright (c) 1998-2007, 2009 Sendmail, 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 17203004SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.683 2009/12/18 01:12:40 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 83090792Sgshapiro#if XLA 83138032Speter if (!xla_host_ok(RealHostName)) 83238032Speter { 83364562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 83490792Sgshapiro finis(false, true, EX_OK); 83538032Speter } 83690792Sgshapiro#endif /* XLA */ 83764562Sgshapiro /* find out name for interface of connection */ 83890792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 83990792Sgshapiro NULL), &sa.sa, &len) == 0) 84064562Sgshapiro { 84164562Sgshapiro p = hostnamebyanyaddr(&sa); 84264562Sgshapiro if (tTd(15, 9)) 84390792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 84490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 84590792Sgshapiro macid("{if_name}"), p); 84664562Sgshapiro 84790792Sgshapiro /* 84890792Sgshapiro ** Do this only if it is not the loopback 84990792Sgshapiro ** interface. 85090792Sgshapiro */ 85190792Sgshapiro 85264562Sgshapiro if (!isloopback(sa)) 85364562Sgshapiro { 85490792Sgshapiro char *addr; 85590792Sgshapiro char family[5]; 85690792Sgshapiro 85790792Sgshapiro addr = anynet_ntoa(&sa); 85890792Sgshapiro (void) sm_snprintf(family, 85990792Sgshapiro sizeof(family), 86090792Sgshapiro "%d", sa.sa.sa_family); 86190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 86290792Sgshapiro A_TEMP, 86390792Sgshapiro macid("{if_addr}"), addr); 86490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 86590792Sgshapiro A_TEMP, 86690792Sgshapiro macid("{if_family}"), family); 86764562Sgshapiro if (tTd(15, 7)) 86890792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 86990792Sgshapiro addr, family); 87064562Sgshapiro } 87164562Sgshapiro else 87264562Sgshapiro { 87390792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87490792Sgshapiro A_PERM, 87590792Sgshapiro macid("{if_addr}"), NULL); 87690792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87790792Sgshapiro A_PERM, 87890792Sgshapiro macid("{if_family}"), NULL); 87964562Sgshapiro } 88064562Sgshapiro } 88164562Sgshapiro else 88264562Sgshapiro { 88364562Sgshapiro if (tTd(15, 7)) 88490792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 88590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 88690792Sgshapiro macid("{if_name}"), NULL); 88790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 88890792Sgshapiro macid("{if_addr}"), NULL); 88990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 89090792Sgshapiro macid("{if_family}"), NULL); 89164562Sgshapiro } 89238032Speter break; 89338032Speter } 89438032Speter 89538032Speter /* parent -- keep track of children */ 89664562Sgshapiro if (control) 89764562Sgshapiro { 898168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 89990792Sgshapiro "control socket server child"); 900132943Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL); 90164562Sgshapiro } 90264562Sgshapiro else 90364562Sgshapiro { 904168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 90590792Sgshapiro "SMTP server child for %s", 90690792Sgshapiro anynet_ntoa(&RealHostAddr)); 907132943Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1, 908132943Sgshapiro &RealHostAddr); 90964562Sgshapiro } 91090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 91138032Speter 91238032Speter /* close the read end of the synchronization pipe */ 91338032Speter if (pipefd[0] != -1) 91464562Sgshapiro { 91538032Speter (void) close(pipefd[0]); 91664562Sgshapiro pipefd[0] = -1; 91764562Sgshapiro } 91838032Speter 91938032Speter /* close the port so that others will hang (for a while) */ 92038032Speter (void) close(t); 92138032Speter 92238032Speter /* release the child by closing the read end of the sync pipe */ 92338032Speter if (pipefd[1] != -1) 92464562Sgshapiro { 92538032Speter (void) close(pipefd[1]); 92664562Sgshapiro pipefd[1] = -1; 92764562Sgshapiro } 92838032Speter } 92990792Sgshapiro if (tTd(15, 2)) 93090792Sgshapiro sm_dprintf("getreq: returning\n"); 93164562Sgshapiro 93290792Sgshapiro#if MILTER 93390792Sgshapiro /* set the filters for this daemon */ 93490792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 93590792Sgshapiro { 93690792Sgshapiro for (i = 0; 937110560Sgshapiro (i < MAXFILTERS && 938110560Sgshapiro Daemons[curdaemon].d_inputfilters[i] != NULL); 93990792Sgshapiro i++) 94090792Sgshapiro { 94190792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 94290792Sgshapiro } 94390792Sgshapiro if (i < MAXFILTERS) 94490792Sgshapiro InputFilters[i] = NULL; 94590792Sgshapiro } 94690792Sgshapiro#endif /* MILTER */ 94764562Sgshapiro return &Daemons[curdaemon].d_flags; 94838032Speter} 94990792Sgshapiro 95090792Sgshapiro/* 95190792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 95290792Sgshapiro** 95390792Sgshapiro** Parameters: 95490792Sgshapiro** e -- envelope. 95590792Sgshapiro** 95690792Sgshapiro** Returns: 95790792Sgshapiro** none. 95890792Sgshapiro** 95990792Sgshapiro** Side Effects: 96090792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 96190792Sgshapiro*/ 96290792Sgshapiro 96390792Sgshapirostatic void 96490792Sgshapirogetrequests_checkdiskspace(e) 96590792Sgshapiro ENVELOPE *e; 96690792Sgshapiro{ 96790792Sgshapiro bool logged = false; 96890792Sgshapiro int idx; 96990792Sgshapiro time_t now; 97090792Sgshapiro 97190792Sgshapiro now = curtime(); 97290792Sgshapiro if (now < NextDiskSpaceCheck) 97390792Sgshapiro return; 97490792Sgshapiro 97590792Sgshapiro /* Check if there is available disk space in all queue groups. */ 97690792Sgshapiro if (!enoughdiskspace(0, NULL)) 97790792Sgshapiro { 97890792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 97990792Sgshapiro { 98090792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 98190792Sgshapiro continue; 98290792Sgshapiro 98390792Sgshapiro /* log only if not logged before */ 98490792Sgshapiro if (!logged) 98590792Sgshapiro { 98690792Sgshapiro if (LogLevel > 8) 98790792Sgshapiro sm_syslog(LOG_INFO, NOQID, 98890792Sgshapiro "rejecting new messages: min free: %ld", 98990792Sgshapiro MinBlocksFree); 99090792Sgshapiro sm_setproctitle(true, e, 99190792Sgshapiro "rejecting new messages: min free: %ld", 99290792Sgshapiro MinBlocksFree); 99390792Sgshapiro logged = true; 99490792Sgshapiro } 99590792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 99690792Sgshapiro } 99790792Sgshapiro } 99890792Sgshapiro else 99990792Sgshapiro { 100090792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 100190792Sgshapiro { 100290792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 100390792Sgshapiro continue; 100490792Sgshapiro 100590792Sgshapiro /* log only if not logged before */ 100690792Sgshapiro if (!logged) 100790792Sgshapiro { 100890792Sgshapiro if (LogLevel > 8) 100990792Sgshapiro sm_syslog(LOG_INFO, NOQID, 101090792Sgshapiro "accepting new messages (again)"); 101190792Sgshapiro logged = true; 101290792Sgshapiro } 101390792Sgshapiro 101490792Sgshapiro /* title will be set later */ 101590792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 101690792Sgshapiro } 101790792Sgshapiro } 101890792Sgshapiro 101990792Sgshapiro /* only check disk space once a minute */ 102090792Sgshapiro NextDiskSpaceCheck = now + 60; 102190792Sgshapiro} 102290792Sgshapiro 102390792Sgshapiro/* 102464562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 102538032Speter** 102664562Sgshapiro** Deals with setting all appropriate options. 102738032Speter** 102838032Speter** Parameters: 102964562Sgshapiro** d -- the structure for the daemon to open. 103038032Speter** firsttime -- set if this is the initial open. 103138032Speter** 103238032Speter** Returns: 103338032Speter** Size in bytes of the daemon socket addr. 103438032Speter** 103538032Speter** Side Effects: 103638032Speter** Leaves DaemonSocket set to the open socket. 103738032Speter** Exits if the socket cannot be created. 103838032Speter*/ 103938032Speter 104090792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 104138032Speter 104264562Sgshapirostatic int 104364562Sgshapiroopendaemonsocket(d, firsttime) 104490792Sgshapiro DAEMON_T *d; 104538032Speter bool firsttime; 104638032Speter{ 104738032Speter int on = 1; 104864562Sgshapiro int fdflags; 104964562Sgshapiro SOCKADDR_LEN_T socksize = 0; 105038032Speter int ntries = 0; 105164562Sgshapiro int save_errno; 105238032Speter 105338032Speter if (tTd(15, 2)) 105490792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 105538032Speter 105638032Speter do 105738032Speter { 105838032Speter if (ntries > 0) 105964562Sgshapiro (void) sleep(5); 106064562Sgshapiro if (firsttime || d->d_socket < 0) 106138032Speter { 106290792Sgshapiro#if _FFR_DAEMON_NETUNIX 106390792Sgshapiro# if NETUNIX 106490792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 106590792Sgshapiro { 106690792Sgshapiro int rval; 106790792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 106890792Sgshapiro 106990792Sgshapiro /* if not safe, don't use it */ 107090792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 107190792Sgshapiro RunAsUid, RunAsGid, 107290792Sgshapiro RunAsUserName, sff, 107390792Sgshapiro S_IRUSR|S_IWUSR, NULL); 107490792Sgshapiro if (rval != 0) 107590792Sgshapiro { 107690792Sgshapiro save_errno = errno; 107790792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 107890792Sgshapiro d->d_name, 107990792Sgshapiro d->d_addr.sunix.sun_path); 108090792Sgshapiro goto fail; 108190792Sgshapiro } 108290792Sgshapiro 108390792Sgshapiro /* Don't try to overtake an existing socket */ 108490792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 108590792Sgshapiro } 108690792Sgshapiro# endif /* NETUNIX */ 108790792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */ 108864562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 108964562Sgshapiro SOCK_STREAM, 0); 109064562Sgshapiro if (d->d_socket < 0) 109138032Speter { 109264562Sgshapiro save_errno = errno; 109390792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 109490792Sgshapiro d->d_name); 109590792Sgshapiro fail: 109690792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 109790792Sgshapiro (!transienterror(save_errno) || 109890792Sgshapiro ntries >= MAXOPENTRIES - 1)) 109990792Sgshapiro { 110090792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 110190792Sgshapiro d->d_name); 110290792Sgshapiro setbitn(D_DISABLE, d->d_flags); 110390792Sgshapiro d->d_socket = -1; 110490792Sgshapiro return -1; 110590792Sgshapiro } 110638032Speter severe: 110738032Speter if (LogLevel > 0) 110838032Speter sm_syslog(LOG_ALERT, NOQID, 110990792Sgshapiro "daemon %s: problem creating SMTP socket", 111090792Sgshapiro d->d_name); 111164562Sgshapiro d->d_socket = -1; 111238032Speter continue; 111338032Speter } 111438032Speter 1115110560Sgshapiro if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE) 1116110560Sgshapiro { 1117110560Sgshapiro save_errno = EINVAL; 1118110560Sgshapiro syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", 1119110560Sgshapiro d->d_name, d->d_socket); 1120110560Sgshapiro goto fail; 1121110560Sgshapiro } 1122110560Sgshapiro 112338032Speter /* turn on network debugging? */ 112438032Speter if (tTd(15, 101)) 112564562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 112638032Speter SO_DEBUG, (char *)&on, 1127168515Sgshapiro sizeof(on)); 112838032Speter 112964562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1130168515Sgshapiro SO_REUSEADDR, (char *)&on, sizeof(on)); 113164562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1132168515Sgshapiro SO_KEEPALIVE, (char *)&on, sizeof(on)); 113338032Speter 113490792Sgshapiro#ifdef SO_RCVBUF 113564562Sgshapiro if (d->d_tcprcvbufsize > 0) 113638032Speter { 113764562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 113838032Speter SO_RCVBUF, 113964562Sgshapiro (char *) &d->d_tcprcvbufsize, 114064562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 114164562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 114238032Speter } 114390792Sgshapiro#endif /* SO_RCVBUF */ 114490792Sgshapiro#ifdef SO_SNDBUF 114564562Sgshapiro if (d->d_tcpsndbufsize > 0) 114664562Sgshapiro { 114764562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 114864562Sgshapiro SO_SNDBUF, 114964562Sgshapiro (char *) &d->d_tcpsndbufsize, 115064562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 115164562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 115264562Sgshapiro } 115390792Sgshapiro#endif /* SO_SNDBUF */ 115438032Speter 115564562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 115664562Sgshapiro fcntl(d->d_socket, F_SETFD, 115764562Sgshapiro fdflags | FD_CLOEXEC) == -1) 115838032Speter { 115964562Sgshapiro save_errno = errno; 116064562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 116164562Sgshapiro d->d_name, 116264562Sgshapiro fdflags == -1 ? "get" : "set", 116390792Sgshapiro sm_errstring(save_errno)); 116464562Sgshapiro (void) close(d->d_socket); 116564562Sgshapiro goto severe; 116664562Sgshapiro } 116764562Sgshapiro 116864562Sgshapiro switch (d->d_addr.sa.sa_family) 116964562Sgshapiro { 117090792Sgshapiro#if _FFR_DAEMON_NETUNIX 117190792Sgshapiro# ifdef NETUNIX 117290792Sgshapiro case AF_UNIX: 1173168515Sgshapiro socksize = sizeof(d->d_addr.sunix); 117490792Sgshapiro break; 117590792Sgshapiro# endif /* NETUNIX */ 117690792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 117790792Sgshapiro#if NETINET 117838032Speter case AF_INET: 1179168515Sgshapiro socksize = sizeof(d->d_addr.sin); 118038032Speter break; 118190792Sgshapiro#endif /* NETINET */ 118238032Speter 118390792Sgshapiro#if NETINET6 118464562Sgshapiro case AF_INET6: 1185168515Sgshapiro socksize = sizeof(d->d_addr.sin6); 118664562Sgshapiro break; 118790792Sgshapiro#endif /* NETINET6 */ 118864562Sgshapiro 118990792Sgshapiro#if NETISO 119038032Speter case AF_ISO: 1191168515Sgshapiro socksize = sizeof(d->d_addr.siso); 119238032Speter break; 119390792Sgshapiro#endif /* NETISO */ 119438032Speter 119538032Speter default: 1196168515Sgshapiro socksize = sizeof(d->d_addr); 119738032Speter break; 119838032Speter } 119938032Speter 120064562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 120138032Speter { 120238032Speter /* probably another daemon already */ 120364562Sgshapiro save_errno = errno; 120464562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 120564562Sgshapiro d->d_name); 120664562Sgshapiro (void) close(d->d_socket); 120790792Sgshapiro goto fail; 120838032Speter } 120938032Speter } 121064562Sgshapiro if (!firsttime && 121164562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 121238032Speter { 121364562Sgshapiro save_errno = errno; 121464562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 121564562Sgshapiro d->d_name); 121664562Sgshapiro (void) close(d->d_socket); 121738032Speter goto severe; 121838032Speter } 121938032Speter return socksize; 122064562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 122164562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 122264562Sgshapiro d->d_name); 122364562Sgshapiro /* NOTREACHED */ 122438032Speter return -1; /* avoid compiler warning on IRIX */ 122538032Speter} 122690792Sgshapiro/* 122764562Sgshapiro** SETUPDAEMON -- setup socket for daemon 122864562Sgshapiro** 122964562Sgshapiro** Parameters: 123064562Sgshapiro** daemonaddr -- socket for daemon 123164562Sgshapiro** 123264562Sgshapiro** Returns: 123364562Sgshapiro** port number on which daemon should run 123464562Sgshapiro** 123564562Sgshapiro*/ 123690792Sgshapiro 123790792Sgshapirostatic unsigned short 123864562Sgshapirosetupdaemon(daemonaddr) 123964562Sgshapiro SOCKADDR *daemonaddr; 124064562Sgshapiro{ 124190792Sgshapiro unsigned short port; 124264562Sgshapiro 124364562Sgshapiro /* 124464562Sgshapiro ** Set up the address for the mailer. 124564562Sgshapiro */ 124664562Sgshapiro 124764562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 124864562Sgshapiro { 1249168515Sgshapiro memset(daemonaddr, '\0', sizeof(*daemonaddr)); 125090792Sgshapiro#if NETINET 125164562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 125290792Sgshapiro#endif /* NETINET */ 125364562Sgshapiro } 125464562Sgshapiro 125564562Sgshapiro switch (daemonaddr->sa.sa_family) 125664562Sgshapiro { 125790792Sgshapiro#if NETINET 125864562Sgshapiro case AF_INET: 125964562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 1260182352Sgshapiro daemonaddr->sin.sin_addr.s_addr = 1261182352Sgshapiro LocalDaemon ? htonl(INADDR_LOOPBACK) : INADDR_ANY; 126264562Sgshapiro port = daemonaddr->sin.sin_port; 126364562Sgshapiro break; 126490792Sgshapiro#endif /* NETINET */ 126564562Sgshapiro 126690792Sgshapiro#if NETINET6 126764562Sgshapiro case AF_INET6: 126864562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 1269182352Sgshapiro daemonaddr->sin6.sin6_addr = 1270182352Sgshapiro LocalDaemon ? in6addr_loopback : in6addr_any; 127164562Sgshapiro port = daemonaddr->sin6.sin6_port; 127264562Sgshapiro break; 127390792Sgshapiro#endif /* NETINET6 */ 127464562Sgshapiro 127564562Sgshapiro default: 127664562Sgshapiro /* unknown protocol */ 127764562Sgshapiro port = 0; 127864562Sgshapiro break; 127964562Sgshapiro } 128064562Sgshapiro if (port == 0) 128164562Sgshapiro { 128290792Sgshapiro#ifdef NO_GETSERVBYNAME 128364562Sgshapiro port = htons(25); 128490792Sgshapiro#else /* NO_GETSERVBYNAME */ 128564562Sgshapiro { 128664562Sgshapiro register struct servent *sp; 128764562Sgshapiro 128864562Sgshapiro sp = getservbyname("smtp", "tcp"); 128964562Sgshapiro if (sp == NULL) 129064562Sgshapiro { 129164562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 129264562Sgshapiro port = htons(25); 129364562Sgshapiro } 129464562Sgshapiro else 129564562Sgshapiro port = sp->s_port; 129664562Sgshapiro } 129790792Sgshapiro#endif /* NO_GETSERVBYNAME */ 129864562Sgshapiro } 129964562Sgshapiro 130064562Sgshapiro switch (daemonaddr->sa.sa_family) 130164562Sgshapiro { 130290792Sgshapiro#if NETINET 130364562Sgshapiro case AF_INET: 130464562Sgshapiro daemonaddr->sin.sin_port = port; 130564562Sgshapiro break; 130690792Sgshapiro#endif /* NETINET */ 130764562Sgshapiro 130890792Sgshapiro#if NETINET6 130964562Sgshapiro case AF_INET6: 131064562Sgshapiro daemonaddr->sin6.sin6_port = port; 131164562Sgshapiro break; 131290792Sgshapiro#endif /* NETINET6 */ 131364562Sgshapiro 131464562Sgshapiro default: 131564562Sgshapiro /* unknown protocol */ 131664562Sgshapiro break; 131764562Sgshapiro } 131890792Sgshapiro return port; 131964562Sgshapiro} 132090792Sgshapiro/* 132138032Speter** CLRDAEMON -- reset the daemon connection 132238032Speter** 132338032Speter** Parameters: 132438032Speter** none. 132538032Speter** 132638032Speter** Returns: 132738032Speter** none. 132838032Speter** 132938032Speter** Side Effects: 133038032Speter** releases any resources used by the passive daemon. 133138032Speter*/ 133238032Speter 133338032Spetervoid 133438032Speterclrdaemon() 133538032Speter{ 133664562Sgshapiro int i; 133764562Sgshapiro 133890792Sgshapiro for (i = 0; i < NDaemons; i++) 133964562Sgshapiro { 134064562Sgshapiro if (Daemons[i].d_socket >= 0) 134164562Sgshapiro (void) close(Daemons[i].d_socket); 134264562Sgshapiro Daemons[i].d_socket = -1; 134364562Sgshapiro } 134438032Speter} 134590792Sgshapiro 134690792Sgshapiro/* 134790792Sgshapiro** GETMODIFIERS -- get modifier flags 134890792Sgshapiro** 134990792Sgshapiro** Parameters: 135090792Sgshapiro** v -- the modifiers (input text line). 135190792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 135290792Sgshapiro** 135390792Sgshapiro** Returns: 135490792Sgshapiro** (xallocat()ed) string representation of modifiers. 135590792Sgshapiro** 135690792Sgshapiro** Side Effects: 135790792Sgshapiro** fills in modifiers. 135890792Sgshapiro*/ 135990792Sgshapiro 136090792Sgshapirochar * 136190792Sgshapirogetmodifiers(v, modifiers) 136290792Sgshapiro char *v; 136390792Sgshapiro BITMAP256 modifiers; 136490792Sgshapiro{ 136590792Sgshapiro int l; 136690792Sgshapiro char *h, *f, *flags; 136790792Sgshapiro 136890792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 136990792Sgshapiro l = 3 * strlen(v) + 3; 137090792Sgshapiro 137190792Sgshapiro /* is someone joking? */ 137290792Sgshapiro if (l < 0 || l > 256) 137390792Sgshapiro { 137490792Sgshapiro if (LogLevel > 2) 137590792Sgshapiro sm_syslog(LOG_ERR, NOQID, 137690792Sgshapiro "getmodifiers too long, ignored"); 137790792Sgshapiro return NULL; 137890792Sgshapiro } 137990792Sgshapiro flags = xalloc(l); 138090792Sgshapiro f = flags; 138190792Sgshapiro clrbitmap(modifiers); 138290792Sgshapiro for (h = v; *h != '\0'; h++) 138390792Sgshapiro { 138490792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 138590792Sgshapiro { 138690792Sgshapiro setbitn(*h, modifiers); 138790792Sgshapiro if (flags != f) 138890792Sgshapiro *flags++ = ' '; 138990792Sgshapiro *flags++ = *h; 139090792Sgshapiro if (isupper(*h)) 139190792Sgshapiro *flags++ = *h; 139290792Sgshapiro } 139390792Sgshapiro } 139490792Sgshapiro *flags++ = '\0'; 139590792Sgshapiro return f; 139690792Sgshapiro} 139790792Sgshapiro 139890792Sgshapiro/* 139990792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 140090792Sgshapiro** 140190792Sgshapiro** Parameters: 140290792Sgshapiro** flag -- the flag to test. 140390792Sgshapiro** 140490792Sgshapiro** Returns: 140590792Sgshapiro** true iff all daemons have set flag. 140690792Sgshapiro*/ 140790792Sgshapiro 140890792Sgshapirobool 140990792Sgshapirochkdaemonmodifiers(flag) 141090792Sgshapiro int flag; 141190792Sgshapiro{ 141290792Sgshapiro int i; 141390792Sgshapiro 141490792Sgshapiro for (i = 0; i < NDaemons; i++) 141590792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 141690792Sgshapiro return false; 141790792Sgshapiro return true; 141890792Sgshapiro} 141990792Sgshapiro 142090792Sgshapiro/* 142164562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 142238032Speter** 142338032Speter** Parameters: 142438032Speter** p -- the options line. 142564562Sgshapiro** d -- the daemon structure to fill in. 142638032Speter** 142738032Speter** Returns: 142838032Speter** none. 142938032Speter*/ 143038032Speter 143164562Sgshapirostatic void 143264562Sgshapirosetsockaddroptions(p, d) 1433141858Sgshapiro char *p; 143490792Sgshapiro DAEMON_T *d; 143538032Speter{ 143690792Sgshapiro#if NETISO 143771345Sgshapiro short portno; 143890792Sgshapiro#endif /* NETISO */ 143971345Sgshapiro char *port = NULL; 144071345Sgshapiro char *addr = NULL; 144138032Speter 144290792Sgshapiro#if NETINET 144364562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 144464562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 144590792Sgshapiro#endif /* NETINET */ 1446157001Sgshapiro#if _FFR_SS_PER_DAEMON 1447168515Sgshapiro d->d_supersafe = DPO_NOTSET; 1448157001Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1449157001Sgshapiro d->d_dm = DM_NOTSET; 1450168515Sgshapiro d->d_refuseLA = DPO_NOTSET; 1451168515Sgshapiro d->d_queueLA = DPO_NOTSET; 1452168515Sgshapiro d->d_delayLA = DPO_NOTSET; 1453168515Sgshapiro d->d_maxchildren = DPO_NOTSET; 145464562Sgshapiro 145538032Speter while (p != NULL) 145638032Speter { 145738032Speter register char *f; 145838032Speter register char *v; 145938032Speter 146038032Speter while (isascii(*p) && isspace(*p)) 146138032Speter p++; 146238032Speter if (*p == '\0') 146338032Speter break; 146438032Speter f = p; 146538032Speter p = strchr(p, ','); 146638032Speter if (p != NULL) 146738032Speter *p++ = '\0'; 146838032Speter v = strchr(f, '='); 146938032Speter if (v == NULL) 147038032Speter continue; 147138032Speter while (isascii(*++v) && isspace(*v)) 147238032Speter continue; 147338032Speter 147438032Speter switch (*f) 147538032Speter { 1476147078Sgshapiro case 'A': /* address */ 1477168515Sgshapiro#if !_FFR_DPO_CS 1478168515Sgshapiro case 'a': 1479168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1480147078Sgshapiro addr = v; 1481147078Sgshapiro break; 1482147078Sgshapiro 1483168515Sgshapiro case 'c': 1484168515Sgshapiro d->d_maxchildren = atoi(v); 1485168515Sgshapiro break; 1486168515Sgshapiro 1487147078Sgshapiro case 'D': /* DeliveryMode */ 1488147078Sgshapiro switch (*v) 1489147078Sgshapiro { 1490147078Sgshapiro case SM_QUEUE: 1491147078Sgshapiro case SM_DEFER: 1492147078Sgshapiro case SM_DELIVER: 1493157001Sgshapiro case SM_FORK: 1494147078Sgshapiro d->d_dm = *v; 1495147078Sgshapiro break; 1496147078Sgshapiro default: 1497147078Sgshapiro syserr("554 5.3.5 Unknown delivery mode %c", 1498147078Sgshapiro *v); 1499147078Sgshapiro break; 1500147078Sgshapiro } 1501147078Sgshapiro break; 1502147078Sgshapiro 1503168515Sgshapiro case 'd': /* delayLA */ 1504168515Sgshapiro d->d_delayLA = atoi(v); 1505168515Sgshapiro break; 1506168515Sgshapiro 150738032Speter case 'F': /* address family */ 1508168515Sgshapiro#if !_FFR_DPO_CS 1509168515Sgshapiro case 'f': 1510168515Sgshapiro#endif /* !_FFR_DPO_CS */ 151138032Speter if (isascii(*v) && isdigit(*v)) 151264562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 151390792Sgshapiro#if _FFR_DAEMON_NETUNIX 151490792Sgshapiro# ifdef NETUNIX 151590792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 151690792Sgshapiro sm_strcasecmp(v, "local") == 0) 151790792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 151890792Sgshapiro# endif /* NETUNIX */ 151990792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 152090792Sgshapiro#if NETINET 152190792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 152264562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 152390792Sgshapiro#endif /* NETINET */ 152490792Sgshapiro#if NETINET6 152590792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 152664562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 152790792Sgshapiro#endif /* NETINET6 */ 152890792Sgshapiro#if NETISO 152990792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 153064562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 153190792Sgshapiro#endif /* NETISO */ 153290792Sgshapiro#if NETNS 153390792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 153464562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 153590792Sgshapiro#endif /* NETNS */ 153690792Sgshapiro#if NETX25 153790792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 153864562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 153990792Sgshapiro#endif /* NETX25 */ 154038032Speter else 154164562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 154264562Sgshapiro v); 154338032Speter break; 154438032Speter 154590792Sgshapiro#if MILTER 154690792Sgshapiro case 'I': 1547168515Sgshapiro# if !_FFR_DPO_CS 1548168515Sgshapiro case 'i': 1549168515Sgshapiro# endif /* !_FFR_DPO_CS */ 155090792Sgshapiro d->d_inputfilterlist = v; 155190792Sgshapiro break; 155290792Sgshapiro#endif /* MILTER */ 155390792Sgshapiro 155438032Speter case 'L': /* listen queue size */ 1555168515Sgshapiro#if !_FFR_DPO_CS 1556168515Sgshapiro case 'l': 1557168515Sgshapiro#endif /* !_FFR_DPO_CS */ 155864562Sgshapiro d->d_listenqueue = atoi(v); 155938032Speter break; 156038032Speter 156164562Sgshapiro case 'M': /* modifiers (flags) */ 1562168515Sgshapiro#if !_FFR_DPO_CS 1563168515Sgshapiro case 'm': 1564168515Sgshapiro#endif /* !_FFR_DPO_CS */ 156590792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 156664562Sgshapiro break; 156764562Sgshapiro 1568147078Sgshapiro case 'N': /* name */ 1569168515Sgshapiro#if !_FFR_DPO_CS 1570168515Sgshapiro case 'n': 1571168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1572147078Sgshapiro d->d_name = v; 157338032Speter break; 157438032Speter 1575147078Sgshapiro case 'P': /* port */ 1576168515Sgshapiro#if !_FFR_DPO_CS 1577168515Sgshapiro case 'p': 1578168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1579147078Sgshapiro port = v; 1580147078Sgshapiro break; 1581147078Sgshapiro 1582168515Sgshapiro case 'q': 1583168515Sgshapiro d->d_queueLA = atoi(v); 1584168515Sgshapiro break; 1585168515Sgshapiro 158638032Speter case 'R': /* receive buffer size */ 158764562Sgshapiro d->d_tcprcvbufsize = atoi(v); 158838032Speter break; 158938032Speter 1590168515Sgshapiro case 'r': 1591168515Sgshapiro d->d_refuseLA = atoi(v); 1592168515Sgshapiro break; 1593168515Sgshapiro 1594147078Sgshapiro case 'S': /* send buffer size */ 1595168515Sgshapiro#if !_FFR_DPO_CS 1596168515Sgshapiro case 's': 1597168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1598147078Sgshapiro d->d_tcpsndbufsize = atoi(v); 159964562Sgshapiro break; 160064562Sgshapiro 1601147078Sgshapiro#if _FFR_SS_PER_DAEMON 1602147078Sgshapiro case 'T': /* SuperSafe */ 1603147078Sgshapiro if (tolower(*v) == 'i') 1604147078Sgshapiro d->d_supersafe = SAFE_INTERACTIVE; 1605147078Sgshapiro else if (tolower(*v) == 'p') 1606147078Sgshapiro# if MILTER 1607147078Sgshapiro d->d_supersafe = SAFE_REALLY_POSTMILTER; 1608147078Sgshapiro# else /* MILTER */ 1609147078Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1610147078Sgshapiro "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 1611147078Sgshapiro# endif /* MILTER */ 1612147078Sgshapiro else 1613147078Sgshapiro d->d_supersafe = atobool(v) ? SAFE_REALLY 1614147078Sgshapiro : SAFE_NO; 1615147078Sgshapiro break; 1616147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1617147078Sgshapiro 161838032Speter default: 161964562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 162064562Sgshapiro f); 162138032Speter } 162238032Speter } 162371345Sgshapiro 162471345Sgshapiro /* Check addr and port after finding family */ 162571345Sgshapiro if (addr != NULL) 162671345Sgshapiro { 162771345Sgshapiro switch (d->d_addr.sa.sa_family) 162871345Sgshapiro { 162990792Sgshapiro#if _FFR_DAEMON_NETUNIX 163090792Sgshapiro# if NETUNIX 163190792Sgshapiro case AF_UNIX: 163290792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 163390792Sgshapiro { 163490792Sgshapiro errno = ENAMETOOLONG; 163590792Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %d", 163690792Sgshapiro addr, sizeof(d->d_addr.sunix.sun_path)); 163790792Sgshapiro break; 163890792Sgshapiro } 163990792Sgshapiro 164090792Sgshapiro /* file safety check done in opendaemonsocket() */ 164190792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 164290792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 164390792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 164490792Sgshapiro addr, 164590792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 164690792Sgshapiro break; 164790792Sgshapiro# endif /* NETUNIX */ 164890792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 164990792Sgshapiro#if NETINET 165071345Sgshapiro case AF_INET: 165171345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 165290792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 165390792Sgshapiro == INADDR_NONE)) 165471345Sgshapiro { 165571345Sgshapiro register struct hostent *hp; 165671345Sgshapiro 165771345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 165871345Sgshapiro if (hp == NULL) 165971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 166071345Sgshapiro addr); 166171345Sgshapiro else 166271345Sgshapiro { 166371345Sgshapiro while (*(hp->h_addr_list) != NULL && 166471345Sgshapiro hp->h_addrtype != AF_INET) 166571345Sgshapiro hp->h_addr_list++; 166671345Sgshapiro if (*(hp->h_addr_list) == NULL) 166771345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 166871345Sgshapiro addr); 166971345Sgshapiro else 167071345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 167171345Sgshapiro *(hp->h_addr_list), 167271345Sgshapiro INADDRSZ); 167390792Sgshapiro# if NETINET6 167471345Sgshapiro freehostent(hp); 167571345Sgshapiro hp = NULL; 167690792Sgshapiro# endif /* NETINET6 */ 167771345Sgshapiro } 167871345Sgshapiro } 167971345Sgshapiro break; 168090792Sgshapiro#endif /* NETINET */ 168171345Sgshapiro 168290792Sgshapiro#if NETINET6 168371345Sgshapiro case AF_INET6: 168490792Sgshapiro if (anynet_pton(AF_INET6, addr, 168590792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 168671345Sgshapiro { 168771345Sgshapiro register struct hostent *hp; 168871345Sgshapiro 168971345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 169071345Sgshapiro if (hp == NULL) 169171345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 169271345Sgshapiro addr); 169371345Sgshapiro else 169471345Sgshapiro { 169571345Sgshapiro while (*(hp->h_addr_list) != NULL && 169671345Sgshapiro hp->h_addrtype != AF_INET6) 169771345Sgshapiro hp->h_addr_list++; 169871345Sgshapiro if (*(hp->h_addr_list) == NULL) 169971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 170071345Sgshapiro addr); 170171345Sgshapiro else 170271345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 170371345Sgshapiro *(hp->h_addr_list), 170471345Sgshapiro IN6ADDRSZ); 170571345Sgshapiro freehostent(hp); 170671345Sgshapiro hp = NULL; 170771345Sgshapiro } 170871345Sgshapiro } 170971345Sgshapiro break; 171090792Sgshapiro#endif /* NETINET6 */ 171171345Sgshapiro 171271345Sgshapiro default: 171371345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 171471345Sgshapiro d->d_addr.sa.sa_family); 171571345Sgshapiro break; 171671345Sgshapiro } 171771345Sgshapiro } 171871345Sgshapiro 171971345Sgshapiro if (port != NULL) 172071345Sgshapiro { 172171345Sgshapiro switch (d->d_addr.sa.sa_family) 172271345Sgshapiro { 172390792Sgshapiro#if NETINET 172471345Sgshapiro case AF_INET: 172571345Sgshapiro if (isascii(*port) && isdigit(*port)) 172690792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 172790792Sgshapiro atoi((const char *) port)); 172871345Sgshapiro else 172971345Sgshapiro { 173090792Sgshapiro# ifdef NO_GETSERVBYNAME 173171345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 173271345Sgshapiro port); 173390792Sgshapiro# else /* NO_GETSERVBYNAME */ 173471345Sgshapiro register struct servent *sp; 173571345Sgshapiro 173671345Sgshapiro sp = getservbyname(port, "tcp"); 173771345Sgshapiro if (sp == NULL) 173871345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 173971345Sgshapiro port); 174071345Sgshapiro else 174171345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 174290792Sgshapiro# endif /* NO_GETSERVBYNAME */ 174371345Sgshapiro } 174471345Sgshapiro break; 174590792Sgshapiro#endif /* NETINET */ 174671345Sgshapiro 174790792Sgshapiro#if NETINET6 174871345Sgshapiro case AF_INET6: 174971345Sgshapiro if (isascii(*port) && isdigit(*port)) 175090792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 175190792Sgshapiro atoi(port)); 175271345Sgshapiro else 175371345Sgshapiro { 175490792Sgshapiro# ifdef NO_GETSERVBYNAME 175571345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 175671345Sgshapiro port); 175790792Sgshapiro# else /* NO_GETSERVBYNAME */ 175871345Sgshapiro register struct servent *sp; 175971345Sgshapiro 176071345Sgshapiro sp = getservbyname(port, "tcp"); 176171345Sgshapiro if (sp == NULL) 176271345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 176371345Sgshapiro port); 176471345Sgshapiro else 176571345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 176690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 176771345Sgshapiro } 176871345Sgshapiro break; 176990792Sgshapiro#endif /* NETINET6 */ 177071345Sgshapiro 177190792Sgshapiro#if NETISO 177271345Sgshapiro case AF_ISO: 177371345Sgshapiro /* assume two byte transport selector */ 177471345Sgshapiro if (isascii(*port) && isdigit(*port)) 177590792Sgshapiro portno = htons((unsigned short) atoi(port)); 177671345Sgshapiro else 177771345Sgshapiro { 177890792Sgshapiro# ifdef NO_GETSERVBYNAME 177971345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 178071345Sgshapiro port); 178190792Sgshapiro# else /* NO_GETSERVBYNAME */ 178271345Sgshapiro register struct servent *sp; 178371345Sgshapiro 178471345Sgshapiro sp = getservbyname(port, "tcp"); 178571345Sgshapiro if (sp == NULL) 178671345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 178771345Sgshapiro port); 178871345Sgshapiro else 178971345Sgshapiro portno = sp->s_port; 179090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 179171345Sgshapiro } 179271345Sgshapiro memmove(TSEL(&d->d_addr.siso), 179371345Sgshapiro (char *) &portno, 2); 179471345Sgshapiro break; 179590792Sgshapiro#endif /* NETISO */ 179671345Sgshapiro 179771345Sgshapiro default: 179871345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 179971345Sgshapiro d->d_addr.sa.sa_family); 180071345Sgshapiro break; 180171345Sgshapiro } 180271345Sgshapiro } 180338032Speter} 180490792Sgshapiro/* 180564562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 180638032Speter** 180738032Speter** Parameters: 180864562Sgshapiro** p -- the options line. 180964562Sgshapiro** 181064562Sgshapiro** Returns: 181190792Sgshapiro** true if successful, false otherwise. 181290792Sgshapiro** 181390792Sgshapiro** Side Effects: 181490792Sgshapiro** increments number of daemons. 181564562Sgshapiro*/ 181664562Sgshapiro 181790792Sgshapiro#define DEF_LISTENQUEUE 10 181890792Sgshapiro 181998841Sgshapirostruct dflags 182098841Sgshapiro{ 182198841Sgshapiro char *d_name; 182298841Sgshapiro int d_flag; 182398841Sgshapiro}; 182498841Sgshapiro 182598841Sgshapirostatic struct dflags DaemonFlags[] = 182698841Sgshapiro{ 182798841Sgshapiro { "AUTHREQ", D_AUTHREQ }, 182898841Sgshapiro { "BINDIF", D_BINDIF }, 182998841Sgshapiro { "CANONREQ", D_CANONREQ }, 183098841Sgshapiro { "IFNHELO", D_IFNHELO }, 183198841Sgshapiro { "FQMAIL", D_FQMAIL }, 183298841Sgshapiro { "FQRCPT", D_FQRCPT }, 183398841Sgshapiro { "SMTPS", D_SMTPS }, 183498841Sgshapiro { "UNQUALOK", D_UNQUALOK }, 183598841Sgshapiro { "NOAUTH", D_NOAUTH }, 183698841Sgshapiro { "NOCANON", D_NOCANON }, 183798841Sgshapiro { "NOETRN", D_NOETRN }, 183898841Sgshapiro { "NOTLS", D_NOTLS }, 183998841Sgshapiro { "ETRNONLY", D_ETRNONLY }, 184098841Sgshapiro { "OPTIONAL", D_OPTIONAL }, 184198841Sgshapiro { "DISABLE", D_DISABLE }, 184298841Sgshapiro { "ISSET", D_ISSET }, 184398841Sgshapiro { NULL, 0 } 184498841Sgshapiro}; 184598841Sgshapiro 184698841Sgshapirostatic void 184798841Sgshapiroprintdaemonflags(d) 184898841Sgshapiro DAEMON_T *d; 184998841Sgshapiro{ 185098841Sgshapiro register struct dflags *df; 185198841Sgshapiro bool first = true; 185298841Sgshapiro 185398841Sgshapiro for (df = DaemonFlags; df->d_name != NULL; df++) 185498841Sgshapiro { 185598841Sgshapiro if (!bitnset(df->d_flag, d->d_flags)) 185698841Sgshapiro continue; 185798841Sgshapiro if (first) 1858132943Sgshapiro sm_dprintf("<%s", df->d_name); 185998841Sgshapiro else 1860132943Sgshapiro sm_dprintf(",%s", df->d_name); 186198841Sgshapiro first = false; 186298841Sgshapiro } 186398841Sgshapiro if (!first) 1864132943Sgshapiro sm_dprintf(">"); 186598841Sgshapiro} 186698841Sgshapiro 186764562Sgshapirobool 186864562Sgshapirosetdaemonoptions(p) 186964562Sgshapiro register char *p; 187064562Sgshapiro{ 187190792Sgshapiro if (NDaemons >= MAXDAEMONS) 187290792Sgshapiro return false; 187390792Sgshapiro Daemons[NDaemons].d_socket = -1; 187490792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 187590792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 187690792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 187764562Sgshapiro 187890792Sgshapiro#if MILTER 187990792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 188090792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 188190792Sgshapiro#endif /* MILTER */ 188290792Sgshapiro 188390792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 188490792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 188564562Sgshapiro else 188664562Sgshapiro { 188764562Sgshapiro char num[30]; 188864562Sgshapiro 1889168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Daemon%d", NDaemons); 189090792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 189164562Sgshapiro } 189264562Sgshapiro 189364562Sgshapiro if (tTd(37, 1)) 189464562Sgshapiro { 189590792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 189698841Sgshapiro printdaemonflags(&Daemons[NDaemons]); 189790792Sgshapiro sm_dprintf("\n"); 189864562Sgshapiro } 189990792Sgshapiro ++NDaemons; 190090792Sgshapiro return true; 190164562Sgshapiro} 190290792Sgshapiro/* 190364562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 190464562Sgshapiro** 190564562Sgshapiro** Parameters: 190664562Sgshapiro** none 190764562Sgshapiro** 190864562Sgshapiro** Returns: 190964562Sgshapiro** none 191064562Sgshapiro** 191164562Sgshapiro** Side Effects: 191264562Sgshapiro** initializes structure for one daemon. 191364562Sgshapiro*/ 191490792Sgshapiro 191564562Sgshapirovoid 191664562Sgshapiroinitdaemon() 191764562Sgshapiro{ 191890792Sgshapiro if (NDaemons == 0) 191964562Sgshapiro { 192090792Sgshapiro Daemons[NDaemons].d_socket = -1; 192190792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 192290792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 192390792Sgshapiro NDaemons = 1; 192464562Sgshapiro } 192564562Sgshapiro} 192690792Sgshapiro/* 192764562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 192864562Sgshapiro** 192964562Sgshapiro** Parameters: 193064562Sgshapiro** p -- the options line. 193164562Sgshapiro** 193264562Sgshapiro** Returns: 193364562Sgshapiro** none. 193464562Sgshapiro*/ 193564562Sgshapiro 193690792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 193764562Sgshapiro 193864562Sgshapirovoid 193964562Sgshapirosetclientoptions(p) 194064562Sgshapiro register char *p; 194164562Sgshapiro{ 194290792Sgshapiro int family; 194390792Sgshapiro DAEMON_T d; 194464562Sgshapiro 1945168515Sgshapiro memset(&d, '\0', sizeof(d)); 194664562Sgshapiro setsockaddroptions(p, &d); 194764562Sgshapiro 194864562Sgshapiro /* grab what we need */ 194990792Sgshapiro family = d.d_addr.sa.sa_family; 195090792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 195190792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 195290792Sgshapiro if (d.d_name != NULL) 195390792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 195464562Sgshapiro else 195590792Sgshapiro { 195690792Sgshapiro char num[30]; 195790792Sgshapiro 1958168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Client%d", family); 195990792Sgshapiro ClientSettings[family].d_name = newstr(num); 196090792Sgshapiro } 196164562Sgshapiro} 196290792Sgshapiro/* 196364562Sgshapiro** ADDR_FAMILY -- determine address family from address 196464562Sgshapiro** 196564562Sgshapiro** Parameters: 196664562Sgshapiro** addr -- the string representation of the address 196764562Sgshapiro** 196864562Sgshapiro** Returns: 196964562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 197064562Sgshapiro** 197164562Sgshapiro** Side Effects: 197264562Sgshapiro** none. 197364562Sgshapiro*/ 197464562Sgshapiro 197564562Sgshapirostatic int 197664562Sgshapiroaddr_family(addr) 197764562Sgshapiro char *addr; 197864562Sgshapiro{ 197990792Sgshapiro#if NETINET6 198064562Sgshapiro SOCKADDR clt_addr; 198190792Sgshapiro#endif /* NETINET6 */ 198264562Sgshapiro 198390792Sgshapiro#if NETINET 198464562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 198564562Sgshapiro { 198664562Sgshapiro if (tTd(16, 9)) 198790792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 198864562Sgshapiro return AF_INET; 198964562Sgshapiro } 199090792Sgshapiro#endif /* NETINET */ 199190792Sgshapiro#if NETINET6 199290792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 199364562Sgshapiro { 199464562Sgshapiro if (tTd(16, 9)) 199590792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 199664562Sgshapiro return AF_INET6; 199764562Sgshapiro } 199890792Sgshapiro#endif /* NETINET6 */ 199990792Sgshapiro#if _FFR_DAEMON_NETUNIX 200090792Sgshapiro# if NETUNIX 200190792Sgshapiro if (*addr == '/') 200290792Sgshapiro { 200390792Sgshapiro if (tTd(16, 9)) 200490792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 200590792Sgshapiro return AF_UNIX; 200690792Sgshapiro } 200790792Sgshapiro# endif /* NETUNIX */ 200890792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 200964562Sgshapiro if (tTd(16, 9)) 201090792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 201164562Sgshapiro return AF_UNSPEC; 201264562Sgshapiro} 201390792Sgshapiro 201490792Sgshapiro/* 201590792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 201690792Sgshapiro** 201790792Sgshapiro** Parameters: 201890792Sgshapiro** flag -- the flag to test. 201990792Sgshapiro** 202090792Sgshapiro** Returns: 202190792Sgshapiro** true iff all configured clients have set the flag. 202290792Sgshapiro*/ 202390792Sgshapiro 202490792Sgshapirobool 202590792Sgshapirochkclientmodifiers(flag) 202690792Sgshapiro int flag; 202790792Sgshapiro{ 202890792Sgshapiro int i; 202990792Sgshapiro bool flagisset; 203090792Sgshapiro 203190792Sgshapiro flagisset = false; 203290792Sgshapiro for (i = 0; i < AF_MAX; i++) 203390792Sgshapiro { 203490792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 203590792Sgshapiro { 203690792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 203790792Sgshapiro return false; 203890792Sgshapiro flagisset = true; 203990792Sgshapiro } 204090792Sgshapiro } 204190792Sgshapiro return flagisset; 204290792Sgshapiro} 204390792Sgshapiro 204490792Sgshapiro#if MILTER 204590792Sgshapiro/* 204690792Sgshapiro** SETUP_DAEMON_FILTERS -- Parse per-socket filters 204790792Sgshapiro** 204890792Sgshapiro** Parameters: 204990792Sgshapiro** none 205090792Sgshapiro** 205190792Sgshapiro** Returns: 205290792Sgshapiro** none 205390792Sgshapiro*/ 205490792Sgshapiro 205590792Sgshapirovoid 205690792Sgshapirosetup_daemon_milters() 205790792Sgshapiro{ 205890792Sgshapiro int idx; 205990792Sgshapiro 206090792Sgshapiro if (OpMode == MD_SMTP) 206190792Sgshapiro { 206290792Sgshapiro /* no need to configure the daemons */ 206390792Sgshapiro return; 206490792Sgshapiro } 206590792Sgshapiro 206690792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 206790792Sgshapiro { 206890792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 206990792Sgshapiro { 207090792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 207190792Sgshapiro Daemons[idx].d_inputfilters, 207290792Sgshapiro MAXFILTERS); 207390792Sgshapiro } 207490792Sgshapiro } 207590792Sgshapiro} 207690792Sgshapiro#endif /* MILTER */ 207790792Sgshapiro/* 207864562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 207964562Sgshapiro** 208064562Sgshapiro** Parameters: 208138032Speter** host -- the name of the host. 208238032Speter** port -- the port number to connect to. 208338032Speter** mci -- a pointer to the mail connection information 208438032Speter** structure to be filled in. 208538032Speter** e -- the current envelope. 208690792Sgshapiro** enough -- time at which to stop further connection attempts. 208790792Sgshapiro** (0 means no limit) 208838032Speter** 208938032Speter** Returns: 209038032Speter** An exit code telling whether the connection could be 209138032Speter** made and if not why not. 209238032Speter** 209338032Speter** Side Effects: 209438032Speter** none. 209538032Speter*/ 209638032Speter 209738032Speterstatic jmp_buf CtxConnectTimeout; 209838032Speter 209938032SpeterSOCKADDR CurHostAddr; /* address of current host */ 210038032Speter 210138032Speterint 210290792Sgshapiromakeconnection(host, port, mci, e, enough) 210338032Speter char *host; 210490792Sgshapiro volatile unsigned int port; 210538032Speter register MCI *mci; 210638032Speter ENVELOPE *e; 210790792Sgshapiro time_t enough; 210838032Speter{ 210938032Speter register volatile int addrno = 0; 211090792Sgshapiro volatile int s; 211190792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 211238032Speter SOCKADDR addr; 211364562Sgshapiro SOCKADDR clt_addr; 211464562Sgshapiro int save_errno = 0; 211564562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 2116159609Sgshapiro volatile bool firstconnect = true; 211790792Sgshapiro SM_EVENT *volatile ev = NULL; 211890792Sgshapiro#if NETINET6 211990792Sgshapiro volatile bool v6found = false; 212090792Sgshapiro#endif /* NETINET6 */ 212164562Sgshapiro volatile int family = InetMode; 212264562Sgshapiro SOCKADDR_LEN_T len; 212364562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 212464562Sgshapiro volatile bool clt_bind; 212564562Sgshapiro BITMAP256 d_flags; 212664562Sgshapiro char *p; 212764562Sgshapiro extern ENVELOPE BlankEnvelope; 212838032Speter 212990792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 213064562Sgshapiro clrbitmap(d_flags); 213190792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 213264562Sgshapiro { 213364562Sgshapiro for (; *p != '\0'; p++) 213464562Sgshapiro { 213564562Sgshapiro if (!(isascii(*p) && isspace(*p))) 213671345Sgshapiro setbitn(bitidx(*p), d_flags); 213764562Sgshapiro } 213864562Sgshapiro } 213964562Sgshapiro 214090792Sgshapiro#if NETINET6 214164562Sgshapiro v4retry: 214290792Sgshapiro#endif /* NETINET6 */ 214390792Sgshapiro clt_bind = false; 214464562Sgshapiro 214564562Sgshapiro /* Set up the address for outgoing connection. */ 214664562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 214790792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 214873188Sgshapiro *p != '\0') 214964562Sgshapiro { 215090792Sgshapiro#if NETINET6 215164562Sgshapiro char p6[INET6_ADDRSTRLEN]; 215290792Sgshapiro#endif /* NETINET6 */ 215364562Sgshapiro 2154168515Sgshapiro memset(&clt_addr, '\0', sizeof(clt_addr)); 215564562Sgshapiro 215664562Sgshapiro /* infer the address family from the address itself */ 215764562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 215864562Sgshapiro switch (clt_addr.sa.sa_family) 215964562Sgshapiro { 216090792Sgshapiro#if NETINET 216164562Sgshapiro case AF_INET: 216273188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 216373188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 2164203004Sgshapiro clt_addr.sin.sin_addr.s_addr != 2165203004Sgshapiro htonl(INADDR_LOOPBACK)) 216664562Sgshapiro { 216790792Sgshapiro clt_bind = true; 2168168515Sgshapiro socksize = sizeof(struct sockaddr_in); 216964562Sgshapiro } 217064562Sgshapiro break; 217190792Sgshapiro#endif /* NETINET */ 217264562Sgshapiro 217390792Sgshapiro#if NETINET6 217464562Sgshapiro case AF_INET6: 217564562Sgshapiro if (inet_addr(p) != INADDR_NONE) 2176168515Sgshapiro (void) sm_snprintf(p6, sizeof(p6), 217790792Sgshapiro "IPv6:::ffff:%s", p); 217864562Sgshapiro else 2179168515Sgshapiro (void) sm_strlcpy(p6, p, sizeof(p6)); 218090792Sgshapiro if (anynet_pton(AF_INET6, p6, 218190792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 218273188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 218364562Sgshapiro { 218490792Sgshapiro clt_bind = true; 2185168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 218664562Sgshapiro } 218764562Sgshapiro break; 218890792Sgshapiro#endif /* NETINET6 */ 218964562Sgshapiro 219090792Sgshapiro#if 0 219164562Sgshapiro default: 219264562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 219364562Sgshapiro clt_addr.sa.sa_family); 219464562Sgshapiro break; 219590792Sgshapiro#endif /* 0 */ 219664562Sgshapiro } 219764562Sgshapiro if (clt_bind) 219864562Sgshapiro family = clt_addr.sa.sa_family; 219964562Sgshapiro } 220090792Sgshapiro 220190792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 220290792Sgshapiro if (!clt_bind) 220364562Sgshapiro { 220490792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 220564562Sgshapiro switch (clt_addr.sa.sa_family) 220664562Sgshapiro { 220790792Sgshapiro#if NETINET 220864562Sgshapiro case AF_INET: 220964562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 2210182352Sgshapiro clt_addr.sin.sin_addr.s_addr = LocalDaemon ? 2211182352Sgshapiro htonl(INADDR_LOOPBACK) : INADDR_ANY; 221264562Sgshapiro else 221390792Sgshapiro clt_bind = true; 221464562Sgshapiro if (clt_addr.sin.sin_port != 0) 221590792Sgshapiro clt_bind = true; 2216168515Sgshapiro socksize = sizeof(struct sockaddr_in); 221764562Sgshapiro break; 221890792Sgshapiro#endif /* NETINET */ 221990792Sgshapiro#if NETINET6 222064562Sgshapiro case AF_INET6: 222164562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 2222182352Sgshapiro clt_addr.sin6.sin6_addr = LocalDaemon ? 2223182352Sgshapiro in6addr_loopback : in6addr_any; 222464562Sgshapiro else 222590792Sgshapiro clt_bind = true; 2226168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 222764562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 222890792Sgshapiro clt_bind = true; 222964562Sgshapiro break; 223090792Sgshapiro#endif /* NETINET6 */ 223190792Sgshapiro#if NETISO 223264562Sgshapiro case AF_ISO: 2233168515Sgshapiro socksize = sizeof(clt_addr.siso); 223490792Sgshapiro clt_bind = true; 223564562Sgshapiro break; 223690792Sgshapiro#endif /* NETISO */ 223764562Sgshapiro default: 223864562Sgshapiro break; 223964562Sgshapiro } 224064562Sgshapiro } 224164562Sgshapiro 224238032Speter /* 224338032Speter ** Set up the address for the mailer. 224438032Speter ** Accept "[a.b.c.d]" syntax for host name. 224538032Speter */ 224638032Speter 224773188Sgshapiro SM_SET_H_ERRNO(0); 224838032Speter errno = 0; 2249168515Sgshapiro memset(&CurHostAddr, '\0', sizeof(CurHostAddr)); 2250168515Sgshapiro memset(&addr, '\0', sizeof(addr)); 225138032Speter SmtpPhase = mci->mci_phase = "initial connection"; 225238032Speter CurHostName = host; 225338032Speter 225438032Speter if (host[0] == '[') 225538032Speter { 225664562Sgshapiro p = strchr(host, ']'); 225738032Speter if (p != NULL) 225838032Speter { 225990792Sgshapiro#if NETINET 226064562Sgshapiro unsigned long hid = INADDR_NONE; 226190792Sgshapiro#endif /* NETINET */ 226290792Sgshapiro#if NETINET6 226364562Sgshapiro struct sockaddr_in6 hid6; 226490792Sgshapiro#endif /* NETINET6 */ 226564562Sgshapiro 226638032Speter *p = '\0'; 226790792Sgshapiro#if NETINET6 2268168515Sgshapiro memset(&hid6, '\0', sizeof(hid6)); 226990792Sgshapiro#endif /* NETINET6 */ 227090792Sgshapiro#if NETINET 227164562Sgshapiro if (family == AF_INET && 227264562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 227338032Speter { 227464562Sgshapiro addr.sin.sin_family = AF_INET; 227564562Sgshapiro addr.sin.sin_addr.s_addr = hid; 227664562Sgshapiro } 227764562Sgshapiro else 227890792Sgshapiro#endif /* NETINET */ 227990792Sgshapiro#if NETINET6 228064562Sgshapiro if (family == AF_INET6 && 228190792Sgshapiro anynet_pton(AF_INET6, &host[1], 228290792Sgshapiro &hid6.sin6_addr) == 1) 228364562Sgshapiro { 228464562Sgshapiro addr.sin6.sin6_family = AF_INET6; 228564562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 228664562Sgshapiro } 228764562Sgshapiro else 228890792Sgshapiro#endif /* NETINET6 */ 228964562Sgshapiro { 229038032Speter /* try it as a host name (avoid MX lookup) */ 229164562Sgshapiro hp = sm_gethostbyname(&host[1], family); 229238032Speter if (hp == NULL && p[-1] == '.') 229338032Speter { 229490792Sgshapiro#if NAMED_BIND 229538032Speter int oldopts = _res.options; 229638032Speter 229738032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 229890792Sgshapiro#endif /* NAMED_BIND */ 229938032Speter p[-1] = '\0'; 230064562Sgshapiro hp = sm_gethostbyname(&host[1], 230164562Sgshapiro family); 230238032Speter p[-1] = '.'; 230390792Sgshapiro#if NAMED_BIND 230438032Speter _res.options = oldopts; 230590792Sgshapiro#endif /* NAMED_BIND */ 230638032Speter } 230738032Speter *p = ']'; 230838032Speter goto gothostent; 230938032Speter } 231038032Speter *p = ']'; 231138032Speter } 231238032Speter if (p == NULL) 231338032Speter { 231438032Speter extern char MsgBuf[]; 231538032Speter 231664562Sgshapiro usrerrenh("5.1.2", 231764562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 231864562Sgshapiro host); 231938032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 232064562Sgshapiro errno = EINVAL; 232138032Speter return EX_NOHOST; 232238032Speter } 232338032Speter } 232438032Speter else 232538032Speter { 232638032Speter /* contortion to get around SGI cc complaints */ 232738032Speter { 232864562Sgshapiro p = &host[strlen(host) - 1]; 232964562Sgshapiro hp = sm_gethostbyname(host, family); 233038032Speter if (hp == NULL && *p == '.') 233138032Speter { 233290792Sgshapiro#if NAMED_BIND 233338032Speter int oldopts = _res.options; 233438032Speter 233538032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 233690792Sgshapiro#endif /* NAMED_BIND */ 233738032Speter *p = '\0'; 233864562Sgshapiro hp = sm_gethostbyname(host, family); 233938032Speter *p = '.'; 234090792Sgshapiro#if NAMED_BIND 234138032Speter _res.options = oldopts; 234290792Sgshapiro#endif /* NAMED_BIND */ 234338032Speter } 234438032Speter } 234538032Spetergothostent: 2346203004Sgshapiro if (hp == NULL || hp->h_addr == NULL) 234738032Speter { 234890792Sgshapiro#if NAMED_BIND 234938032Speter /* check for name server timeouts */ 235090792Sgshapiro# if NETINET6 235190792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 235290792Sgshapiro errno == ETIMEDOUT) 235338032Speter { 235490792Sgshapiro /* 235590792Sgshapiro ** An attempt with family AF_INET may 235690792Sgshapiro ** succeed By skipping the next section 235790792Sgshapiro ** of code, we will try AF_INET before 235890792Sgshapiro ** failing. 235990792Sgshapiro */ 236090792Sgshapiro 236190792Sgshapiro if (tTd(16, 10)) 236290792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 236338032Speter } 236490792Sgshapiro else 236590792Sgshapiro# endif /* NETINET6 */ 236690792Sgshapiro { 236790792Sgshapiro if (errno == ETIMEDOUT || 2368168515Sgshapiro# if _FFR_GETHBN_ExFILE 2369168515Sgshapiro# ifdef EMFILE 2370168515Sgshapiro errno == EMFILE || 2371168515Sgshapiro# endif /* EMFILE */ 2372168515Sgshapiro# ifdef ENFILE 2373168515Sgshapiro errno == ENFILE || 2374168515Sgshapiro# endif /* ENFILE */ 2375168515Sgshapiro# endif /* _FFR_GETHBN_ExFILE */ 237690792Sgshapiro h_errno == TRY_AGAIN || 237790792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 237890792Sgshapiro { 237990792Sgshapiro save_errno = errno; 238090792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 238190792Sgshapiro "4.4.3", NULL); 238290792Sgshapiro errno = save_errno; 238390792Sgshapiro return EX_TEMPFAIL; 238490792Sgshapiro } 238590792Sgshapiro } 238690792Sgshapiro#endif /* NAMED_BIND */ 238790792Sgshapiro#if NETINET6 238864562Sgshapiro /* 238964562Sgshapiro ** Try v6 first, then fall back to v4. 239064562Sgshapiro ** If we found a v6 address, but no v4 239164562Sgshapiro ** addresses, then TEMPFAIL. 239264562Sgshapiro */ 239364562Sgshapiro 239464562Sgshapiro if (family == AF_INET6) 239564562Sgshapiro { 239664562Sgshapiro family = AF_INET; 239764562Sgshapiro goto v4retry; 239864562Sgshapiro } 239964562Sgshapiro if (v6found) 240064562Sgshapiro goto v6tempfail; 240190792Sgshapiro#endif /* NETINET6 */ 240264562Sgshapiro save_errno = errno; 240338032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 240464562Sgshapiro errno = save_errno; 240564562Sgshapiro return EX_NOHOST; 240638032Speter } 240738032Speter addr.sa.sa_family = hp->h_addrtype; 240838032Speter switch (hp->h_addrtype) 240938032Speter { 241090792Sgshapiro#if NETINET 241138032Speter case AF_INET: 241264562Sgshapiro memmove(&addr.sin.sin_addr, 241364562Sgshapiro hp->h_addr, 241438032Speter INADDRSZ); 241538032Speter break; 241690792Sgshapiro#endif /* NETINET */ 241738032Speter 241890792Sgshapiro#if NETINET6 241964562Sgshapiro case AF_INET6: 242064562Sgshapiro memmove(&addr.sin6.sin6_addr, 242164562Sgshapiro hp->h_addr, 242264562Sgshapiro IN6ADDRSZ); 242364562Sgshapiro break; 242490792Sgshapiro#endif /* NETINET6 */ 242564562Sgshapiro 242638032Speter default: 2427168515Sgshapiro if (hp->h_length > sizeof(addr.sa.sa_data)) 242838032Speter { 242938032Speter syserr("makeconnection: long sa_data: family %d len %d", 243038032Speter hp->h_addrtype, hp->h_length); 243138032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 243264562Sgshapiro errno = EINVAL; 243338032Speter return EX_NOHOST; 243438032Speter } 243590792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 243638032Speter break; 243738032Speter } 243838032Speter addrno = 1; 243938032Speter } 244038032Speter 244138032Speter /* 244238032Speter ** Determine the port number. 244338032Speter */ 244438032Speter 244538032Speter if (port == 0) 244638032Speter { 244790792Sgshapiro#ifdef NO_GETSERVBYNAME 244864562Sgshapiro port = htons(25); 244990792Sgshapiro#else /* NO_GETSERVBYNAME */ 245038032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 245138032Speter 245238032Speter if (sp == NULL) 245338032Speter { 245438032Speter if (LogLevel > 2) 245538032Speter sm_syslog(LOG_ERR, NOQID, 245664562Sgshapiro "makeconnection: service \"smtp\" unknown"); 245738032Speter port = htons(25); 245838032Speter } 245938032Speter else 246038032Speter port = sp->s_port; 246190792Sgshapiro#endif /* NO_GETSERVBYNAME */ 246238032Speter } 246338032Speter 246490792Sgshapiro#if NETINET6 246590792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 246690792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 246790792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 246890792Sgshapiro { 246990792Sgshapiro /* 247090792Sgshapiro ** Ignore mapped IPv4 address since 247190792Sgshapiro ** there is a ClientPortOptions setting 247290792Sgshapiro ** for IPv4. 247390792Sgshapiro */ 247490792Sgshapiro 247590792Sgshapiro goto nextaddr; 247690792Sgshapiro } 247790792Sgshapiro#endif /* NETINET6 */ 247890792Sgshapiro 247938032Speter switch (addr.sa.sa_family) 248038032Speter { 248190792Sgshapiro#if NETINET 248238032Speter case AF_INET: 248338032Speter addr.sin.sin_port = port; 2484168515Sgshapiro addrlen = sizeof(struct sockaddr_in); 248538032Speter break; 248690792Sgshapiro#endif /* NETINET */ 248738032Speter 248890792Sgshapiro#if NETINET6 248964562Sgshapiro case AF_INET6: 249064562Sgshapiro addr.sin6.sin6_port = port; 2491168515Sgshapiro addrlen = sizeof(struct sockaddr_in6); 249264562Sgshapiro break; 249390792Sgshapiro#endif /* NETINET6 */ 249464562Sgshapiro 249590792Sgshapiro#if NETISO 249638032Speter case AF_ISO: 249738032Speter /* assume two byte transport selector */ 249864562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 2499168515Sgshapiro addrlen = sizeof(struct sockaddr_iso); 250038032Speter break; 250190792Sgshapiro#endif /* NETISO */ 250238032Speter 250338032Speter default: 250438032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 250538032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 250664562Sgshapiro errno = EINVAL; 250790792Sgshapiro#if NETINET6 250871345Sgshapiro if (hp != NULL) 250971345Sgshapiro freehostent(hp); 251090792Sgshapiro#endif /* NETINET6 */ 251164562Sgshapiro return EX_NOHOST; 251238032Speter } 251338032Speter 251438032Speter /* 251538032Speter ** Try to actually open the connection. 251638032Speter */ 251738032Speter 251890792Sgshapiro#if XLA 251938032Speter /* if too many connections, don't bother trying */ 252038032Speter if (!xla_noqueue_ok(host)) 252171345Sgshapiro { 252290792Sgshapiro# if NETINET6 252371345Sgshapiro if (hp != NULL) 252471345Sgshapiro freehostent(hp); 252590792Sgshapiro# endif /* NETINET6 */ 252638032Speter return EX_TEMPFAIL; 252771345Sgshapiro } 252890792Sgshapiro#endif /* XLA */ 252938032Speter 253038032Speter for (;;) 253138032Speter { 253238032Speter if (tTd(16, 1)) 253390792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 253490792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 253590792Sgshapiro (int) addr.sa.sa_family); 253638032Speter 253738032Speter /* save for logging */ 253838032Speter CurHostAddr = addr; 253938032Speter 254090792Sgshapiro#if HASRRESVPORT 254138032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 254238032Speter { 254338032Speter int rport = IPPORT_RESERVED - 1; 254438032Speter 254538032Speter s = rresvport(&rport); 254638032Speter } 254738032Speter else 254890792Sgshapiro#endif /* HASRRESVPORT */ 254938032Speter { 255090792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 255138032Speter } 255238032Speter if (s < 0) 255338032Speter { 255464562Sgshapiro save_errno = errno; 255538032Speter syserr("makeconnection: cannot create socket"); 255690792Sgshapiro#if XLA 255738032Speter xla_host_end(host); 255890792Sgshapiro#endif /* XLA */ 255938032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 256090792Sgshapiro#if NETINET6 256171345Sgshapiro if (hp != NULL) 256271345Sgshapiro freehostent(hp); 256390792Sgshapiro#endif /* NETINET6 */ 256464562Sgshapiro errno = save_errno; 256538032Speter return EX_TEMPFAIL; 256638032Speter } 256738032Speter 256890792Sgshapiro#ifdef SO_SNDBUF 256990792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 257038032Speter { 257138032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 257290792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 257390792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 257438032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 257538032Speter } 257690792Sgshapiro#endif /* SO_SNDBUF */ 257790792Sgshapiro#ifdef SO_RCVBUF 257890792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 257964562Sgshapiro { 258064562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 258190792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 258290792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 258364562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 258464562Sgshapiro } 258590792Sgshapiro#endif /* SO_RCVBUF */ 258638032Speter 258738032Speter if (tTd(16, 1)) 258890792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 258938032Speter 259038032Speter /* turn on network debugging? */ 259138032Speter if (tTd(16, 101)) 259238032Speter { 259338032Speter int on = 1; 259464562Sgshapiro 259538032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 2596168515Sgshapiro (char *)&on, sizeof(on)); 259738032Speter } 259890792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 259990792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 260090792Sgshapiro errno = 0; /* for debugging */ 260138032Speter 260264562Sgshapiro if (clt_bind) 260364562Sgshapiro { 260464562Sgshapiro int on = 1; 260564562Sgshapiro 260664562Sgshapiro switch (clt_addr.sa.sa_family) 260764562Sgshapiro { 260890792Sgshapiro#if NETINET 260964562Sgshapiro case AF_INET: 261064562Sgshapiro if (clt_addr.sin.sin_port != 0) 261164562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 261264562Sgshapiro SO_REUSEADDR, 261364562Sgshapiro (char *) &on, 2614168515Sgshapiro sizeof(on)); 261564562Sgshapiro break; 261690792Sgshapiro#endif /* NETINET */ 261764562Sgshapiro 261890792Sgshapiro#if NETINET6 261964562Sgshapiro case AF_INET6: 262064562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 262164562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 262264562Sgshapiro SO_REUSEADDR, 262364562Sgshapiro (char *) &on, 2624168515Sgshapiro sizeof(on)); 262564562Sgshapiro break; 262690792Sgshapiro#endif /* NETINET6 */ 262764562Sgshapiro } 262864562Sgshapiro 262964562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 263064562Sgshapiro { 263164562Sgshapiro save_errno = errno; 263264562Sgshapiro (void) close(s); 263364562Sgshapiro errno = save_errno; 263464562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 263564562Sgshapiro anynet_ntoa(&clt_addr)); 263690792Sgshapiro#if NETINET6 263771345Sgshapiro if (hp != NULL) 263871345Sgshapiro freehostent(hp); 263990792Sgshapiro#endif /* NETINET6 */ 264064562Sgshapiro errno = save_errno; 264164562Sgshapiro return EX_TEMPFAIL; 264264562Sgshapiro } 264364562Sgshapiro } 264464562Sgshapiro 264538032Speter /* 264638032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 264738032Speter ** Time out the connect to avoid this problem. 264838032Speter */ 264938032Speter 265038032Speter if (setjmp(CtxConnectTimeout) == 0) 265138032Speter { 265238032Speter int i; 265338032Speter 265438032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 265590792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 265690792Sgshapiro connecttimeout, 0); 265738032Speter else if (TimeOuts.to_connect != 0) 265890792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 265990792Sgshapiro connecttimeout, 0); 266038032Speter else 266138032Speter ev = NULL; 266238032Speter 266364562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 266464562Sgshapiro { 266590792Sgshapiro#if NETINET 266664562Sgshapiro case AF_INET: 266764562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 266864562Sgshapiro break; 266990792Sgshapiro#endif /* NETINET */ 267064562Sgshapiro 267190792Sgshapiro#if NETINET6 267264562Sgshapiro case AF_INET6: 267364562Sgshapiro memmove(&addr.sin6.sin6_addr, 267464562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 267564562Sgshapiro IN6ADDRSZ); 267664562Sgshapiro break; 267790792Sgshapiro#endif /* NETINET6 */ 267864562Sgshapiro } 2679141858Sgshapiro if (tTd(16, 1)) 2680141858Sgshapiro sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr)); 268138032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 268264562Sgshapiro save_errno = errno; 268338032Speter if (ev != NULL) 268490792Sgshapiro sm_clrevent(ev); 268538032Speter if (i >= 0) 268638032Speter break; 268738032Speter } 268838032Speter else 268964562Sgshapiro save_errno = errno; 269038032Speter 269194334Sgshapiro /* couldn't connect.... figure out why */ 269294334Sgshapiro (void) close(s); 269394334Sgshapiro 269438032Speter /* if running demand-dialed connection, try again */ 269590792Sgshapiro if (DialDelay > 0 && firstconnect && 269690792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 269738032Speter { 269838032Speter if (tTd(16, 1)) 269990792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 270090792Sgshapiro sm_errstring(save_errno)); 270190792Sgshapiro firstconnect = false; 270264562Sgshapiro (void) sleep(DialDelay); 270338032Speter continue; 270438032Speter } 270538032Speter 270690792Sgshapiro if (LogLevel > 13) 270738032Speter sm_syslog(LOG_INFO, e->e_id, 270838032Speter "makeconnection (%s [%s]) failed: %s", 270938032Speter host, anynet_ntoa(&addr), 271090792Sgshapiro sm_errstring(save_errno)); 271138032Speter 271290792Sgshapiro#if NETINET6 271390792Sgshapironextaddr: 271490792Sgshapiro#endif /* NETINET6 */ 271590792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 271690792Sgshapiro (enough == 0 || curtime() < enough)) 271738032Speter { 271838032Speter if (tTd(16, 1)) 271990792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 272090792Sgshapiro sm_errstring(save_errno)); 272138032Speter switch (addr.sa.sa_family) 272238032Speter { 272390792Sgshapiro#if NETINET 272438032Speter case AF_INET: 272564562Sgshapiro memmove(&addr.sin.sin_addr, 272664562Sgshapiro hp->h_addr_list[addrno++], 272764562Sgshapiro INADDRSZ); 272838032Speter break; 272990792Sgshapiro#endif /* NETINET */ 273038032Speter 273190792Sgshapiro#if NETINET6 273264562Sgshapiro case AF_INET6: 273364562Sgshapiro memmove(&addr.sin6.sin6_addr, 273464562Sgshapiro hp->h_addr_list[addrno++], 273564562Sgshapiro IN6ADDRSZ); 273664562Sgshapiro break; 273790792Sgshapiro#endif /* NETINET6 */ 273864562Sgshapiro 273938032Speter default: 274064562Sgshapiro memmove(addr.sa.sa_data, 274164562Sgshapiro hp->h_addr_list[addrno++], 274238032Speter hp->h_length); 274338032Speter break; 274438032Speter } 274538032Speter continue; 274638032Speter } 274764562Sgshapiro errno = save_errno; 274838032Speter 274990792Sgshapiro#if NETINET6 275064562Sgshapiro if (family == AF_INET6) 275164562Sgshapiro { 275264562Sgshapiro if (tTd(16, 1)) 275390792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 275490792Sgshapiro sm_errstring(save_errno)); 275590792Sgshapiro v6found = true; 275664562Sgshapiro family = AF_INET; 275771345Sgshapiro if (hp != NULL) 275871345Sgshapiro { 275971345Sgshapiro freehostent(hp); 276071345Sgshapiro hp = NULL; 276171345Sgshapiro } 276264562Sgshapiro goto v4retry; 276364562Sgshapiro } 276464562Sgshapiro v6tempfail: 276590792Sgshapiro#endif /* NETINET6 */ 276638032Speter /* couldn't open connection */ 276790792Sgshapiro#if NETINET6 276864562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 276964562Sgshapiro if (errno > 0) 277090792Sgshapiro#endif /* NETINET6 */ 277164562Sgshapiro save_errno = errno; 277264562Sgshapiro if (tTd(16, 1)) 277390792Sgshapiro sm_dprintf("Connect failed (%s)\n", 277490792Sgshapiro sm_errstring(save_errno)); 277590792Sgshapiro#if XLA 277638032Speter xla_host_end(host); 277790792Sgshapiro#endif /* XLA */ 277838032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 277990792Sgshapiro#if NETINET6 278071345Sgshapiro if (hp != NULL) 278171345Sgshapiro freehostent(hp); 278290792Sgshapiro#endif /* NETINET6 */ 278364562Sgshapiro errno = save_errno; 278438032Speter return EX_TEMPFAIL; 278538032Speter } 278638032Speter 278790792Sgshapiro#if NETINET6 278871345Sgshapiro if (hp != NULL) 278971345Sgshapiro { 279071345Sgshapiro freehostent(hp); 279171345Sgshapiro hp = NULL; 279271345Sgshapiro } 279390792Sgshapiro#endif /* NETINET6 */ 279471345Sgshapiro 279538032Speter /* connection ok, put it into canonical form */ 279664562Sgshapiro mci->mci_out = NULL; 279790792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 279890792Sgshapiro (void *) &s, 2799132943Sgshapiro SM_IO_WRONLY_B, NULL)) == NULL || 280038032Speter (s = dup(s)) < 0 || 280190792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 280290792Sgshapiro (void *) &s, 2803132943Sgshapiro SM_IO_RDONLY_B, NULL)) == NULL) 280438032Speter { 280564562Sgshapiro save_errno = errno; 280638032Speter syserr("cannot open SMTP client channel, fd=%d", s); 280738032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 280864562Sgshapiro if (mci->mci_out != NULL) 280990792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 281064562Sgshapiro (void) close(s); 281164562Sgshapiro errno = save_errno; 281238032Speter return EX_TEMPFAIL; 281338032Speter } 281490792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 281538032Speter 281690792Sgshapiro /* set {client_flags} */ 281790792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 281890792Sgshapiro { 281990792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 282090792Sgshapiro macid("{client_flags}"), 282190792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 282290792Sgshapiro } 282390792Sgshapiro else 282490792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 282590792Sgshapiro macid("{client_flags}"), ""); 282690792Sgshapiro 282790792Sgshapiro /* "add" {client_flags} to bitmap */ 282890792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 282990792Sgshapiro { 283090792Sgshapiro /* look for just this one flag */ 283190792Sgshapiro setbitn(D_IFNHELO, d_flags); 283290792Sgshapiro } 283390792Sgshapiro 283464562Sgshapiro /* find out name for Interface through which we connect */ 2835168515Sgshapiro len = sizeof(addr); 283664562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 283764562Sgshapiro { 283864562Sgshapiro char *name; 283990792Sgshapiro char family[5]; 284064562Sgshapiro 284190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 284290792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 284390792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 284490792Sgshapiro addr.sa.sa_family); 284590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 284690792Sgshapiro macid("{if_family_out}"), family); 284764562Sgshapiro 284864562Sgshapiro name = hostnamebyanyaddr(&addr); 284990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 285090792Sgshapiro macid("{if_name_out}"), name); 285164562Sgshapiro if (LogLevel > 11) 285264562Sgshapiro { 285364562Sgshapiro /* log connection information */ 285464562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 285564562Sgshapiro "SMTP outgoing connect on %.40s", name); 285664562Sgshapiro } 285764562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 285864562Sgshapiro { 285964562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 286064562Sgshapiro mci->mci_heloname = newstr(name); 286164562Sgshapiro } 286264562Sgshapiro } 286364562Sgshapiro else 286464562Sgshapiro { 286590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 286690792Sgshapiro macid("{if_name_out}"), NULL); 286790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 286890792Sgshapiro macid("{if_addr_out}"), NULL); 286990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287090792Sgshapiro macid("{if_family_out}"), NULL); 287164562Sgshapiro } 2872132943Sgshapiro 2873132943Sgshapiro /* Use the configured HeloName as appropriate */ 2874132943Sgshapiro if (HeloName != NULL && HeloName[0] != '\0') 2875132943Sgshapiro mci->mci_heloname = newstr(HeloName); 2876132943Sgshapiro 287738032Speter mci_setstat(mci, EX_OK, NULL, NULL); 287864562Sgshapiro return EX_OK; 287938032Speter} 288064562Sgshapiro 288164562Sgshapirostatic void 2882141858Sgshapiroconnecttimeout(ignore) 2883141858Sgshapiro int ignore; 288464562Sgshapiro{ 288577349Sgshapiro /* 288677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 288777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 288877349Sgshapiro ** DOING. 288977349Sgshapiro */ 289077349Sgshapiro 289164562Sgshapiro errno = ETIMEDOUT; 289264562Sgshapiro longjmp(CtxConnectTimeout, 1); 289364562Sgshapiro} 289490792Sgshapiro/* 289564562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 289664562Sgshapiro** 289764562Sgshapiro** Parameters: 289864562Sgshapiro** mux_path -- the path of the socket to connect to. 289964562Sgshapiro** mci -- a pointer to the mail connection information 290064562Sgshapiro** structure to be filled in. 290164562Sgshapiro** 290264562Sgshapiro** Returns: 290364562Sgshapiro** An exit code telling whether the connection could be 290464562Sgshapiro** made and if not why not. 290564562Sgshapiro** 290664562Sgshapiro** Side Effects: 290764562Sgshapiro** none. 290864562Sgshapiro*/ 290964562Sgshapiro 291090792Sgshapiro#if NETUNIX 291190792Sgshapiroint 291290792Sgshapiromakeconnection_ds(mux_path, mci) 291364562Sgshapiro char *mux_path; 291464562Sgshapiro register MCI *mci; 291564562Sgshapiro{ 291664562Sgshapiro int sock; 291764562Sgshapiro int rval, save_errno; 291864562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 291964562Sgshapiro struct sockaddr_un unix_addr; 292064562Sgshapiro 292164562Sgshapiro /* if not safe, don't connect */ 292264562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 292364562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 292464562Sgshapiro 292564562Sgshapiro if (rval != 0) 292664562Sgshapiro { 2927132943Sgshapiro syserr("makeconnection_ds: unsafe domain socket %s", 2928132943Sgshapiro mux_path); 292964562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 293064562Sgshapiro errno = rval; 293164562Sgshapiro return EX_TEMPFAIL; 293264562Sgshapiro } 293364562Sgshapiro 293464562Sgshapiro /* prepare address structure */ 2935168515Sgshapiro memset(&unix_addr, '\0', sizeof(unix_addr)); 293664562Sgshapiro unix_addr.sun_family = AF_UNIX; 293764562Sgshapiro 2938168515Sgshapiro if (strlen(mux_path) >= sizeof(unix_addr.sun_path)) 293964562Sgshapiro { 2940132943Sgshapiro syserr("makeconnection_ds: domain socket name %s too long", 2941132943Sgshapiro mux_path); 294290792Sgshapiro 294390792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 294464562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 294564562Sgshapiro errno = ENAMETOOLONG; 294664562Sgshapiro return EX_UNAVAILABLE; 294764562Sgshapiro } 294890792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 2949168515Sgshapiro sizeof(unix_addr.sun_path)); 295064562Sgshapiro 295164562Sgshapiro /* initialize domain socket */ 295264562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 295364562Sgshapiro if (sock == -1) 295464562Sgshapiro { 295564562Sgshapiro save_errno = errno; 2956132943Sgshapiro syserr("makeconnection_ds: could not create domain socket %s", 2957132943Sgshapiro mux_path); 295864562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 295964562Sgshapiro errno = save_errno; 296064562Sgshapiro return EX_TEMPFAIL; 296164562Sgshapiro } 296264562Sgshapiro 296364562Sgshapiro /* connect to server */ 296464562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 296564562Sgshapiro sizeof(unix_addr)) == -1) 296664562Sgshapiro { 296764562Sgshapiro save_errno = errno; 296864562Sgshapiro syserr("Could not connect to socket %s", mux_path); 296964562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 297064562Sgshapiro (void) close(sock); 297164562Sgshapiro errno = save_errno; 297264562Sgshapiro return EX_TEMPFAIL; 297364562Sgshapiro } 297464562Sgshapiro 297564562Sgshapiro /* connection ok, put it into canonical form */ 297664562Sgshapiro mci->mci_out = NULL; 297790792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2978132943Sgshapiro (void *) &sock, SM_IO_WRONLY_B, NULL)) 297990792Sgshapiro == NULL 298090792Sgshapiro || (sock = dup(sock)) < 0 || 298190792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2982132943Sgshapiro (void *) &sock, SM_IO_RDONLY_B, NULL)) 298390792Sgshapiro == NULL) 298464562Sgshapiro { 298564562Sgshapiro save_errno = errno; 298664562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 298764562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 298864562Sgshapiro if (mci->mci_out != NULL) 298990792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 299064562Sgshapiro (void) close(sock); 299164562Sgshapiro errno = save_errno; 299264562Sgshapiro return EX_TEMPFAIL; 299364562Sgshapiro } 299490792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 299564562Sgshapiro 299664562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 299764562Sgshapiro errno = 0; 299864562Sgshapiro return EX_OK; 299964562Sgshapiro} 300090792Sgshapiro#endif /* NETUNIX */ 300190792Sgshapiro/* 300290792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 300377349Sgshapiro** 300477349Sgshapiro** Parameters: 300590792Sgshapiro** none. 300677349Sgshapiro** 300777349Sgshapiro** Returns: 300877349Sgshapiro** none. 300977349Sgshapiro** 301077349Sgshapiro** Side Effects: 301190792Sgshapiro** closes control socket, exits. 301277349Sgshapiro*/ 301377349Sgshapiro 301490792Sgshapirovoid 301590792Sgshapiroshutdown_daemon() 301677349Sgshapiro{ 301790792Sgshapiro int i; 301890792Sgshapiro char *reason; 301977349Sgshapiro 302090792Sgshapiro sm_allsignals(true); 302190792Sgshapiro 302290792Sgshapiro reason = ShutdownRequest; 302390792Sgshapiro ShutdownRequest = NULL; 302490792Sgshapiro PendingSignal = 0; 302590792Sgshapiro 3026132943Sgshapiro if (LogLevel > 9) 3027132943Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s", 302890792Sgshapiro reason == NULL ? "implicit call" : reason); 302990792Sgshapiro 303090792Sgshapiro FileName = NULL; 303190792Sgshapiro closecontrolsocket(true); 303290792Sgshapiro#if XLA 303390792Sgshapiro xla_all_end(); 303490792Sgshapiro#endif /* XLA */ 303590792Sgshapiro 303690792Sgshapiro for (i = 0; i < NDaemons; i++) 303790792Sgshapiro { 303890792Sgshapiro if (Daemons[i].d_socket >= 0) 303990792Sgshapiro { 304090792Sgshapiro (void) close(Daemons[i].d_socket); 304190792Sgshapiro Daemons[i].d_socket = -1; 304290792Sgshapiro 304390792Sgshapiro#if _FFR_DAEMON_NETUNIX 304490792Sgshapiro# if NETUNIX 304590792Sgshapiro /* Remove named sockets */ 304690792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 304790792Sgshapiro { 304890792Sgshapiro int rval; 304990792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 305090792Sgshapiro 305190792Sgshapiro /* if not safe, don't use it */ 305290792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 305390792Sgshapiro RunAsUid, RunAsGid, 305490792Sgshapiro RunAsUserName, sff, 305590792Sgshapiro S_IRUSR|S_IWUSR, NULL); 305690792Sgshapiro if (rval == 0 && 305790792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 305890792Sgshapiro { 305990792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 306090792Sgshapiro "Could not remove daemon %s socket: %s: %s", 306190792Sgshapiro Daemons[i].d_name, 306290792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 306390792Sgshapiro sm_errstring(errno)); 306490792Sgshapiro } 306590792Sgshapiro } 306690792Sgshapiro# endif /* NETUNIX */ 306790792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 306890792Sgshapiro } 306990792Sgshapiro } 307090792Sgshapiro 307190792Sgshapiro finis(false, true, EX_OK); 307277349Sgshapiro} 307390792Sgshapiro/* 307477349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 307577349Sgshapiro** 307677349Sgshapiro** Parameters: 307777349Sgshapiro** none. 307877349Sgshapiro** 307977349Sgshapiro** Returns: 308077349Sgshapiro** none. 308177349Sgshapiro** 308277349Sgshapiro** Side Effects: 308377349Sgshapiro** restarts the daemon or exits if restart fails. 308477349Sgshapiro*/ 308577349Sgshapiro 308680785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 308780785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 308880785Sgshapirodo \ 308980785Sgshapiro{ \ 309090792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 309180785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 309290792Sgshapiro (void) sm_signal((sig), (old)); \ 309380785Sgshapiro} while (0) 309480785Sgshapiro 309590792Sgshapirovoid 309677349Sgshapirorestart_daemon() 309777349Sgshapiro{ 309890792Sgshapiro bool drop; 309977349Sgshapiro int save_errno; 310077349Sgshapiro char *reason; 310180785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 310277349Sgshapiro extern int DtableSize; 310377349Sgshapiro 310480785Sgshapiro /* clear the events to turn off SIGALRMs */ 310590792Sgshapiro sm_clear_events(); 310690792Sgshapiro sm_allsignals(true); 310777349Sgshapiro 310877349Sgshapiro reason = RestartRequest; 310977349Sgshapiro RestartRequest = NULL; 311077349Sgshapiro PendingSignal = 0; 311177349Sgshapiro 311277349Sgshapiro if (SaveArgv[0][0] != '/') 311377349Sgshapiro { 311477349Sgshapiro if (LogLevel > 3) 311577349Sgshapiro sm_syslog(LOG_INFO, NOQID, 311677349Sgshapiro "could not restart: need full path"); 311790792Sgshapiro finis(false, true, EX_OSFILE); 311890792Sgshapiro /* NOTREACHED */ 311977349Sgshapiro } 312077349Sgshapiro if (LogLevel > 3) 312177349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 312277349Sgshapiro SaveArgv[0], 312377349Sgshapiro reason == NULL ? "implicit call" : reason); 312477349Sgshapiro 312590792Sgshapiro closecontrolsocket(true); 312698121Sgshapiro#if SM_CONF_SHM 312798121Sgshapiro cleanup_shm(DaemonPid == getpid()); 312898121Sgshapiro#endif /* SM_CONF_SHM */ 312990792Sgshapiro 3130132943Sgshapiro /* close locked pid file */ 3131132943Sgshapiro close_sendmail_pid(); 3132132943Sgshapiro 313390792Sgshapiro /* 313490792Sgshapiro ** Want to drop to the user who started the process in all cases 313590792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 313690792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 313790792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 313890792Sgshapiro */ 313990792Sgshapiro 314090792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 314190792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 314290792Sgshapiro 314390792Sgshapiro if (drop_privileges(drop) != EX_OK) 314477349Sgshapiro { 314577349Sgshapiro if (LogLevel > 0) 314677349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 314790792Sgshapiro "could not drop privileges: %s", 314890792Sgshapiro sm_errstring(errno)); 314990792Sgshapiro finis(false, true, EX_OSERR); 315090792Sgshapiro /* NOTREACHED */ 315177349Sgshapiro } 315277349Sgshapiro 3153132943Sgshapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 315477349Sgshapiro 315580785Sgshapiro /* 315680785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 315780785Sgshapiro ** However, the default action can be "terminate", so it isn't 315880785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 315980785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 316080785Sgshapiro */ 316180785Sgshapiro 316280785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 316380785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 316480785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 316580785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 316680785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 316780785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 316880785Sgshapiro#ifdef SIGUSR1 316980785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 317080785Sgshapiro#endif /* SIGUSR1 */ 317194334Sgshapiro 317294334Sgshapiro /* Turn back on signals */ 317390792Sgshapiro sm_allsignals(false); 317477349Sgshapiro 317577349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 317677349Sgshapiro save_errno = errno; 317777349Sgshapiro 317880785Sgshapiro /* block signals again and restore needed signals */ 317990792Sgshapiro sm_allsignals(true); 318080785Sgshapiro 318180785Sgshapiro /* For finis() events */ 318290792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 318380785Sgshapiro 318480785Sgshapiro#ifdef SIGUSR1 318580785Sgshapiro /* For debugging finis() */ 318690792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 318780785Sgshapiro#endif /* SIGUSR1 */ 318877349Sgshapiro 318977349Sgshapiro errno = save_errno; 319077349Sgshapiro if (LogLevel > 0) 319190792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 319290792Sgshapiro SaveArgv[0], sm_errstring(errno)); 319390792Sgshapiro finis(false, true, EX_OSFILE); 319490792Sgshapiro /* NOTREACHED */ 319577349Sgshapiro} 319690792Sgshapiro/* 319738032Speter** MYHOSTNAME -- return the name of this host. 319838032Speter** 319938032Speter** Parameters: 320038032Speter** hostbuf -- a place to return the name of this host. 320138032Speter** size -- the size of hostbuf. 320238032Speter** 320338032Speter** Returns: 320438032Speter** A list of aliases for this host. 320538032Speter** 320638032Speter** Side Effects: 320738032Speter** Adds numeric codes to $=w. 320838032Speter*/ 320938032Speter 321038032Speterstruct hostent * 321138032Spetermyhostname(hostbuf, size) 321238032Speter char hostbuf[]; 321338032Speter int size; 321438032Speter{ 321538032Speter register struct hostent *hp; 321638032Speter 321773188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 321890792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 321964562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 322090792Sgshapiro#if NETINET && NETINET6 322180785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 322280785Sgshapiro { 322380785Sgshapiro /* 322480785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 322580785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 322680785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 322780785Sgshapiro */ 322880785Sgshapiro 322980785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 323080785Sgshapiro } 323190792Sgshapiro#endif /* NETINET && NETINET6 */ 323238032Speter if (hp == NULL) 323338032Speter return NULL; 323438032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 323564562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 323664562Sgshapiro 323790792Sgshapiro#if NETINFO 323864562Sgshapiro if (strchr(hostbuf, '.') == NULL) 323938032Speter { 324064562Sgshapiro char *domainname; 324164562Sgshapiro 324264562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 324364562Sgshapiro "domain", '\0'); 324464562Sgshapiro if (domainname != NULL && 324564562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 324690792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 324738032Speter } 324890792Sgshapiro#endif /* NETINFO */ 324938032Speter 325038032Speter /* 325138032Speter ** If there is still no dot in the name, try looking for a 325238032Speter ** dotted alias. 325338032Speter */ 325438032Speter 325538032Speter if (strchr(hostbuf, '.') == NULL) 325638032Speter { 325738032Speter char **ha; 325838032Speter 325964562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 326038032Speter { 326138032Speter if (strchr(*ha, '.') != NULL) 326238032Speter { 326364562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 326438032Speter hostbuf[size - 1] = '\0'; 326538032Speter break; 326638032Speter } 326738032Speter } 326838032Speter } 326938032Speter 327038032Speter /* 327138032Speter ** If _still_ no dot, wait for a while and try again -- it is 327238032Speter ** possible that some service is starting up. This can result 327338032Speter ** in excessive delays if the system is badly configured, but 327438032Speter ** there really isn't a way around that, particularly given that 327538032Speter ** the config file hasn't been read at this point. 327638032Speter ** All in all, a bit of a mess. 327738032Speter */ 327838032Speter 327938032Speter if (strchr(hostbuf, '.') == NULL && 328090792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 328138032Speter { 3282182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_CRIT, NOQID, 328364562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 328464562Sgshapiro hostbuf); 328538032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 328638032Speter hostbuf); 328764562Sgshapiro (void) sleep(60); 328890792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 328938032Speter { 3290182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_ALERT, NOQID, 329164562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 329264562Sgshapiro hostbuf); 329338032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 329438032Speter hostbuf); 329538032Speter } 329638032Speter } 329764562Sgshapiro return hp; 329838032Speter} 329990792Sgshapiro/* 330038032Speter** ADDRCMP -- compare two host addresses 330138032Speter** 330238032Speter** Parameters: 330338032Speter** hp -- hostent structure for the first address 330438032Speter** ha -- actual first address 330538032Speter** sa -- second address 330638032Speter** 330738032Speter** Returns: 330838032Speter** 0 -- if ha and sa match 330938032Speter** else -- they don't match 331038032Speter*/ 331138032Speter 331264562Sgshapirostatic int 331338032Speteraddrcmp(hp, ha, sa) 331438032Speter struct hostent *hp; 331538032Speter char *ha; 331638032Speter SOCKADDR *sa; 331738032Speter{ 331890792Sgshapiro#if NETINET6 331990792Sgshapiro unsigned char *a; 332090792Sgshapiro#endif /* NETINET6 */ 332164562Sgshapiro 332238032Speter switch (sa->sa.sa_family) 332338032Speter { 332490792Sgshapiro#if NETINET 332538032Speter case AF_INET: 332638032Speter if (hp->h_addrtype == AF_INET) 332764562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 332838032Speter break; 332990792Sgshapiro#endif /* NETINET */ 333038032Speter 333190792Sgshapiro#if NETINET6 333264562Sgshapiro case AF_INET6: 333390792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 333464562Sgshapiro 333564562Sgshapiro /* Straight binary comparison */ 333664562Sgshapiro if (hp->h_addrtype == AF_INET6) 333764562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 333864562Sgshapiro 333964562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 334064562Sgshapiro if (hp->h_addrtype == AF_INET && 334164562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 334264562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 334364562Sgshapiro break; 334490792Sgshapiro#endif /* NETINET6 */ 334538032Speter } 334638032Speter return -1; 334738032Speter} 334890792Sgshapiro/* 334964562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 335038032Speter** 335138032Speter** Uses RFC1413 protocol to try to get info from the other end. 335238032Speter** 335338032Speter** Parameters: 335438032Speter** fd -- the descriptor 335590792Sgshapiro** may_be_forged -- an outage that is set to true if the 335638032Speter** forward lookup of RealHostName does not match 335790792Sgshapiro** RealHostAddr; set to false if they do match. 335838032Speter** 335938032Speter** Returns: 336038032Speter** The user@host information associated with this descriptor. 336138032Speter*/ 336238032Speter 336338032Speterstatic jmp_buf CtxAuthTimeout; 336438032Speter 336538032Speterstatic void 3366141858Sgshapiroauthtimeout(ignore) 3367141858Sgshapiro int ignore; 336838032Speter{ 336977349Sgshapiro /* 337077349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 337177349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 337277349Sgshapiro ** DOING. 337377349Sgshapiro */ 337477349Sgshapiro 337577349Sgshapiro errno = ETIMEDOUT; 337638032Speter longjmp(CtxAuthTimeout, 1); 337738032Speter} 337838032Speter 337938032Speterchar * 338038032Spetergetauthinfo(fd, may_be_forged) 338138032Speter int fd; 338238032Speter bool *may_be_forged; 338338032Speter{ 338490792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 338538032Speter SOCKADDR_LEN_T falen; 338638032Speter register char *volatile p = NULL; 338738032Speter SOCKADDR la; 338838032Speter SOCKADDR_LEN_T lalen; 338990792Sgshapiro#ifndef NO_GETSERVBYNAME 339038032Speter register struct servent *sp; 339190792Sgshapiro# if NETINET 339290792Sgshapiro static unsigned short port4 = 0; 339390792Sgshapiro# endif /* NETINET */ 339490792Sgshapiro# if NETINET6 339590792Sgshapiro static unsigned short port6 = 0; 339690792Sgshapiro# endif /* NETINET6 */ 339790792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 339838032Speter volatile int s; 339938032Speter int i = 0; 340090792Sgshapiro size_t len; 340190792Sgshapiro SM_EVENT *ev; 340238032Speter int nleft; 340338032Speter struct hostent *hp; 340438032Speter char *ostype = NULL; 340538032Speter char **ha; 340638032Speter char ibuf[MAXNAME + 1]; 3407110560Sgshapiro static char hbuf[MAXNAME + MAXAUTHINFO + 11]; 340838032Speter 340990792Sgshapiro *may_be_forged = false; 3410168515Sgshapiro falen = sizeof(RealHostAddr); 341138032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 341238032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 341338032Speter { 341464562Sgshapiro if (i < 0) 341564562Sgshapiro { 341664562Sgshapiro /* 341764562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 341864562Sgshapiro ** errno in this case, so a mis-report doesn't 341964562Sgshapiro ** happen later. 342064562Sgshapiro */ 342190792Sgshapiro 342264562Sgshapiro if (errno != ENOTSOCK) 342364562Sgshapiro return NULL; 342464562Sgshapiro errno = 0; 342564562Sgshapiro } 3426168515Sgshapiro (void) sm_strlcpyn(hbuf, sizeof(hbuf), 2, RealUserName, 342790792Sgshapiro "@localhost"); 342838032Speter if (tTd(9, 1)) 342990792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 343038032Speter return hbuf; 343138032Speter } 343238032Speter 343338032Speter if (RealHostName == NULL) 343438032Speter { 343538032Speter /* translate that to a host name */ 343638032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 343738032Speter if (strlen(RealHostName) > MAXNAME) 343890792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 343938032Speter } 344038032Speter 344138032Speter /* cross check RealHostName with forward DNS lookup */ 344290792Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] != '[' && 344390792Sgshapiro RealHostName[0] != '[') 344438032Speter { 344580785Sgshapiro int family; 344680785Sgshapiro 344780785Sgshapiro family = RealHostAddr.sa.sa_family; 344890792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 344980785Sgshapiro /* 345080785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 345180785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 345280785Sgshapiro ** address(es) for addrcmp() to compare against 345380785Sgshapiro ** RealHostAddr. 345480785Sgshapiro ** 345580785Sgshapiro ** Actually, we only need to do this for systems 345680785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 345780785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 345880785Sgshapiro ** flag. A better fix to this problem is to add this 345980785Sgshapiro ** functionality to our stub getipnodebyname(). 346080785Sgshapiro */ 346180785Sgshapiro 346280785Sgshapiro if (family == AF_INET6 && 346380785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 346480785Sgshapiro family = AF_INET; 346590792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 346680785Sgshapiro 346738032Speter /* try to match the reverse against the forward lookup */ 346880785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 346938032Speter if (hp == NULL) 3470120256Sgshapiro { 3471132943Sgshapiro /* XXX: Could be a temporary error on forward lookup */ 347290792Sgshapiro *may_be_forged = true; 3473120256Sgshapiro } 347438032Speter else 347538032Speter { 347638032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 347790792Sgshapiro { 347838032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 347938032Speter break; 348090792Sgshapiro } 348138032Speter *may_be_forged = *ha == NULL; 348290792Sgshapiro#if NETINET6 348371345Sgshapiro freehostent(hp); 348471345Sgshapiro hp = NULL; 348590792Sgshapiro#endif /* NETINET6 */ 348638032Speter } 348738032Speter } 348838032Speter 348938032Speter if (TimeOuts.to_ident == 0) 349038032Speter goto noident; 349138032Speter 3492168515Sgshapiro lalen = sizeof(la); 349364562Sgshapiro switch (RealHostAddr.sa.sa_family) 349438032Speter { 349590792Sgshapiro#if NETINET 349664562Sgshapiro case AF_INET: 349764562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 349864562Sgshapiro lalen <= 0 || 349964562Sgshapiro la.sa.sa_family != AF_INET) 350064562Sgshapiro { 350164562Sgshapiro /* no ident info */ 350264562Sgshapiro goto noident; 350364562Sgshapiro } 350464562Sgshapiro port = RealHostAddr.sin.sin_port; 350538032Speter 350664562Sgshapiro /* create ident query */ 3507168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 350864562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 350964562Sgshapiro ntohs(la.sin.sin_port)); 351038032Speter 351164562Sgshapiro /* create local address */ 351264562Sgshapiro la.sin.sin_port = 0; 351338032Speter 351464562Sgshapiro /* create foreign address */ 351590792Sgshapiro# ifdef NO_GETSERVBYNAME 351638032Speter RealHostAddr.sin.sin_port = htons(113); 351790792Sgshapiro# else /* NO_GETSERVBYNAME */ 351890792Sgshapiro 351990792Sgshapiro /* 352090792Sgshapiro ** getservbyname() consumes about 5% of the time 352190792Sgshapiro ** when receiving a small message (almost all of the time 352290792Sgshapiro ** spent in this routine). 352390792Sgshapiro ** Hence we store the port in a static variable 352490792Sgshapiro ** to save this time. 352590792Sgshapiro ** The portnumber shouldn't change very often... 352690792Sgshapiro ** This code makes the assumption that the port number 352790792Sgshapiro ** is not 0. 352890792Sgshapiro */ 352990792Sgshapiro 353090792Sgshapiro if (port4 == 0) 353190792Sgshapiro { 353290792Sgshapiro sp = getservbyname("auth", "tcp"); 353390792Sgshapiro if (sp != NULL) 353490792Sgshapiro port4 = sp->s_port; 353590792Sgshapiro else 353690792Sgshapiro port4 = htons(113); 353790792Sgshapiro } 353890792Sgshapiro RealHostAddr.sin.sin_port = port4; 353964562Sgshapiro break; 354090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 354190792Sgshapiro#endif /* NETINET */ 354238032Speter 354390792Sgshapiro#if NETINET6 354464562Sgshapiro case AF_INET6: 354564562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 354664562Sgshapiro lalen <= 0 || 354764562Sgshapiro la.sa.sa_family != AF_INET6) 354864562Sgshapiro { 354964562Sgshapiro /* no ident info */ 355064562Sgshapiro goto noident; 355164562Sgshapiro } 355264562Sgshapiro port = RealHostAddr.sin6.sin6_port; 355364562Sgshapiro 355464562Sgshapiro /* create ident query */ 3555168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 355664562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 355764562Sgshapiro ntohs(la.sin6.sin6_port)); 355864562Sgshapiro 355964562Sgshapiro /* create local address */ 356064562Sgshapiro la.sin6.sin6_port = 0; 356164562Sgshapiro 356264562Sgshapiro /* create foreign address */ 356390792Sgshapiro# ifdef NO_GETSERVBYNAME 356464562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 356590792Sgshapiro# else /* NO_GETSERVBYNAME */ 356690792Sgshapiro if (port6 == 0) 356790792Sgshapiro { 356890792Sgshapiro sp = getservbyname("auth", "tcp"); 356990792Sgshapiro if (sp != NULL) 357090792Sgshapiro port6 = sp->s_port; 357190792Sgshapiro else 357290792Sgshapiro port6 = htons(113); 357390792Sgshapiro } 357490792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 357564562Sgshapiro break; 357690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 357790792Sgshapiro#endif /* NETINET6 */ 357864562Sgshapiro default: 357964562Sgshapiro /* no ident info */ 358064562Sgshapiro goto noident; 358164562Sgshapiro } 358264562Sgshapiro 358338032Speter s = -1; 358438032Speter if (setjmp(CtxAuthTimeout) != 0) 358538032Speter { 358638032Speter if (s >= 0) 358738032Speter (void) close(s); 358838032Speter goto noident; 358938032Speter } 359038032Speter 359138032Speter /* put a timeout around the whole thing */ 359290792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 359338032Speter 359438032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 359564562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 359638032Speter if (s < 0) 359738032Speter { 359890792Sgshapiro sm_clrevent(ev); 359938032Speter goto noident; 360038032Speter } 360164562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 360264562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 360338032Speter goto closeident; 360438032Speter 360538032Speter if (tTd(9, 10)) 360690792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 360738032Speter 360838032Speter /* send query */ 360938032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 361038032Speter goto closeident; 361138032Speter 361238032Speter /* get result */ 361338032Speter p = &ibuf[0]; 3614168515Sgshapiro nleft = sizeof(ibuf) - 1; 361538032Speter while ((i = read(s, p, nleft)) > 0) 361638032Speter { 3617125820Sgshapiro char *s; 3618125820Sgshapiro 361938032Speter p += i; 362038032Speter nleft -= i; 362138032Speter *p = '\0'; 3622125820Sgshapiro if ((s = strchr(ibuf, '\n')) != NULL) 3623125820Sgshapiro { 3624125820Sgshapiro if (p > s + 1) 3625125820Sgshapiro { 3626125820Sgshapiro p = s + 1; 3627125820Sgshapiro *p = '\0'; 3628125820Sgshapiro } 362938032Speter break; 3630125820Sgshapiro } 3631125820Sgshapiro if (nleft <= 0) 3632125820Sgshapiro break; 363338032Speter } 363438032Speter (void) close(s); 363590792Sgshapiro sm_clrevent(ev); 363638032Speter if (i < 0 || p == &ibuf[0]) 363738032Speter goto noident; 363838032Speter 3639111823Sgshapiro if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r') 364038032Speter p--; 364138032Speter *++p = '\0'; 364238032Speter 364338032Speter if (tTd(9, 3)) 364490792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 364538032Speter 364638032Speter /* parse result */ 364738032Speter p = strchr(ibuf, ':'); 364838032Speter if (p == NULL) 364938032Speter { 365038032Speter /* malformed response */ 365138032Speter goto noident; 365238032Speter } 365338032Speter while (isascii(*++p) && isspace(*p)) 365438032Speter continue; 365590792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 365638032Speter { 365738032Speter /* presumably an error string */ 365838032Speter goto noident; 365938032Speter } 366038032Speter p += 6; 366138032Speter while (isascii(*p) && isspace(*p)) 366238032Speter p++; 366338032Speter if (*p++ != ':') 366438032Speter { 366538032Speter /* either useridxx or malformed response */ 366638032Speter goto noident; 366738032Speter } 366838032Speter 366938032Speter /* p now points to the OSTYPE field */ 367038032Speter while (isascii(*p) && isspace(*p)) 367138032Speter p++; 367238032Speter ostype = p; 367338032Speter p = strchr(p, ':'); 367438032Speter if (p == NULL) 367538032Speter { 367638032Speter /* malformed response */ 367738032Speter goto noident; 367838032Speter } 367938032Speter else 368038032Speter { 368138032Speter char *charset; 368238032Speter 368338032Speter *p = '\0'; 368438032Speter charset = strchr(ostype, ','); 368538032Speter if (charset != NULL) 368638032Speter *charset = '\0'; 368738032Speter } 368838032Speter 368938032Speter /* 1413 says don't do this -- but it's broken otherwise */ 369038032Speter while (isascii(*++p) && isspace(*p)) 369138032Speter continue; 369238032Speter 369338032Speter /* p now points to the authenticated name -- copy carefully */ 369490792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 369538032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 369638032Speter { 3697168515Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof(hbuf)); 3698110560Sgshapiro cleanstrcpy(&hbuf[6], p, MAXAUTHINFO); 369938032Speter } 370038032Speter else 3701110560Sgshapiro cleanstrcpy(hbuf, p, MAXAUTHINFO); 370290792Sgshapiro len = strlen(hbuf); 3703168515Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof(hbuf) - len, 2, "@", 370490792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 370538032Speter goto postident; 370638032Speter 370738032Spetercloseident: 370838032Speter (void) close(s); 370990792Sgshapiro sm_clrevent(ev); 371038032Speter 371138032Speternoident: 371264562Sgshapiro /* put back the original incoming port */ 371364562Sgshapiro switch (RealHostAddr.sa.sa_family) 371464562Sgshapiro { 371590792Sgshapiro#if NETINET 371664562Sgshapiro case AF_INET: 371764562Sgshapiro if (port > 0) 371864562Sgshapiro RealHostAddr.sin.sin_port = port; 371964562Sgshapiro break; 372090792Sgshapiro#endif /* NETINET */ 372164562Sgshapiro 372290792Sgshapiro#if NETINET6 372364562Sgshapiro case AF_INET6: 372464562Sgshapiro if (port > 0) 372564562Sgshapiro RealHostAddr.sin6.sin6_port = port; 372664562Sgshapiro break; 372790792Sgshapiro#endif /* NETINET6 */ 372864562Sgshapiro } 372964562Sgshapiro 373038032Speter if (RealHostName == NULL) 373138032Speter { 373238032Speter if (tTd(9, 1)) 373390792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 373438032Speter return NULL; 373538032Speter } 3736168515Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof(hbuf)); 373738032Speter 373838032Speterpostident: 373990792Sgshapiro#if IP_SRCROUTE 374090792Sgshapiro# ifndef GET_IPOPT_DST 374190792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 374290792Sgshapiro# endif /* ! GET_IPOPT_DST */ 374338032Speter /* 374438032Speter ** Extract IP source routing information. 374538032Speter ** 374638032Speter ** Format of output for a connection from site a through b 374738032Speter ** through c to d: 374838032Speter ** loose: @site-c@site-b:site-a 374938032Speter ** strict: !@site-c@site-b:site-a 375038032Speter ** 375138032Speter ** o - pointer within ipopt_list structure. 375238032Speter ** q - pointer within ls/ss rr route data 375338032Speter ** p - pointer to hbuf 375438032Speter */ 375538032Speter 375638032Speter if (RealHostAddr.sa.sa_family == AF_INET) 375738032Speter { 375838032Speter SOCKOPT_LEN_T ipoptlen; 375938032Speter int j; 376090792Sgshapiro unsigned char *q; 376190792Sgshapiro unsigned char *o; 376238032Speter int l; 376364562Sgshapiro struct IPOPTION ipopt; 376438032Speter 3765168515Sgshapiro ipoptlen = sizeof(ipopt); 376638032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 376738032Speter (char *) &ipopt, &ipoptlen) < 0) 376838032Speter goto noipsr; 376938032Speter if (ipoptlen == 0) 377038032Speter goto noipsr; 377190792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 377290792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 377338032Speter { 377438032Speter switch (*o) 377538032Speter { 377664562Sgshapiro case IPOPT_EOL: 377738032Speter o = NULL; 377838032Speter break; 377938032Speter 378038032Speter case IPOPT_NOP: 378138032Speter o++; 378238032Speter break; 378338032Speter 378438032Speter case IPOPT_SSRR: 378538032Speter case IPOPT_LSRR: 378638032Speter /* 378738032Speter ** Source routing. 378838032Speter ** o[0] is the option type (loose/strict). 378938032Speter ** o[1] is the length of this option, 379038032Speter ** including option type and 379138032Speter ** length. 379238032Speter ** o[2] is the pointer into the route 379338032Speter ** data. 379438032Speter ** o[3] begins the route data. 379538032Speter */ 379638032Speter 379738032Speter p = &hbuf[strlen(hbuf)]; 3798168515Sgshapiro l = sizeof(hbuf) - (hbuf - p) - 6; 379990792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 380090792Sgshapiro " [%s@%.*s", 380190792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 380290792Sgshapiro l > 240 ? 120 : l / 2, 380390792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 380438032Speter i = strlen(p); 380538032Speter p += i; 380638032Speter l -= strlen(p); 380738032Speter 380838032Speter j = o[1] / sizeof(struct in_addr) - 1; 380938032Speter 381038032Speter /* q skips length and router pointer to data */ 381138032Speter q = &o[3]; 381238032Speter for ( ; j >= 0; j--) 381338032Speter { 381464562Sgshapiro struct in_addr addr; 381564562Sgshapiro 381638032Speter memcpy(&addr, q, sizeof(addr)); 381790792Sgshapiro (void) sm_snprintf(p, 381890792Sgshapiro SPACELEFT(hbuf, p), 381990792Sgshapiro "%c%.*s", 382090792Sgshapiro j != 0 ? '@' : ':', 382190792Sgshapiro l > 240 ? 120 : 382290792Sgshapiro j == 0 ? l : l / 2, 382390792Sgshapiro inet_ntoa(addr)); 382438032Speter i = strlen(p); 382538032Speter p += i; 382638032Speter l -= i + 1; 382764562Sgshapiro q += sizeof(struct in_addr); 382838032Speter } 382938032Speter o += o[1]; 383038032Speter break; 383138032Speter 383238032Speter default: 383338032Speter /* Skip over option */ 383438032Speter o += o[1]; 383538032Speter break; 383638032Speter } 383738032Speter } 383890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 383938032Speter goto postipsr; 384038032Speter } 384138032Speter 384238032Speternoipsr: 384390792Sgshapiro#endif /* IP_SRCROUTE */ 384438032Speter if (RealHostName != NULL && RealHostName[0] != '[') 384538032Speter { 384638032Speter p = &hbuf[strlen(hbuf)]; 384790792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 384890792Sgshapiro anynet_ntoa(&RealHostAddr)); 384938032Speter } 385038032Speter if (*may_be_forged) 385138032Speter { 385238032Speter p = &hbuf[strlen(hbuf)]; 385390792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 385490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 385590792Sgshapiro macid("{client_resolve}"), "FORGED"); 385638032Speter } 385738032Speter 385890792Sgshapiro#if IP_SRCROUTE 385938032Speterpostipsr: 386090792Sgshapiro#endif /* IP_SRCROUTE */ 386164562Sgshapiro 386264562Sgshapiro /* put back the original incoming port */ 386364562Sgshapiro switch (RealHostAddr.sa.sa_family) 386464562Sgshapiro { 386590792Sgshapiro#if NETINET 386664562Sgshapiro case AF_INET: 386764562Sgshapiro if (port > 0) 386864562Sgshapiro RealHostAddr.sin.sin_port = port; 386964562Sgshapiro break; 387090792Sgshapiro#endif /* NETINET */ 387164562Sgshapiro 387290792Sgshapiro#if NETINET6 387364562Sgshapiro case AF_INET6: 387464562Sgshapiro if (port > 0) 387564562Sgshapiro RealHostAddr.sin6.sin6_port = port; 387664562Sgshapiro break; 387790792Sgshapiro#endif /* NETINET6 */ 387864562Sgshapiro } 387964562Sgshapiro 388090792Sgshapiro if (tTd(9, 1)) 388190792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 388238032Speter return hbuf; 388338032Speter} 388490792Sgshapiro/* 388538032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 388638032Speter** 388738032Speter** Parameters: 388838032Speter** map -- a pointer to this map. 388938032Speter** name -- the (presumably unqualified) hostname. 389038032Speter** av -- unused -- for compatibility with other mapping 389138032Speter** functions. 389238032Speter** statp -- an exit status (out parameter) -- set to 389338032Speter** EX_TEMPFAIL if the name server is unavailable. 389438032Speter** 389538032Speter** Returns: 389638032Speter** The mapping, if found. 389738032Speter** NULL if no mapping found. 389838032Speter** 389938032Speter** Side Effects: 390038032Speter** Looks up the host specified in hbuf. If it is not 390138032Speter** the canonical name for that host, return the canonical 390238032Speter** name (unless MF_MATCHONLY is set, which will cause the 390338032Speter** status only to be returned). 390438032Speter*/ 390538032Speter 390638032Speterchar * 390738032Speterhost_map_lookup(map, name, av, statp) 390838032Speter MAP *map; 390938032Speter char *name; 391038032Speter char **av; 391138032Speter int *statp; 391238032Speter{ 391338032Speter register struct hostent *hp; 391490792Sgshapiro#if NETINET 391538032Speter struct in_addr in_addr; 391690792Sgshapiro#endif /* NETINET */ 391790792Sgshapiro#if NETINET6 391864562Sgshapiro struct in6_addr in6_addr; 391990792Sgshapiro#endif /* NETINET6 */ 392064562Sgshapiro char *cp, *ans = NULL; 392138032Speter register STAB *s; 392290792Sgshapiro time_t now; 392390792Sgshapiro#if NAMED_BIND 392490792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 392590792Sgshapiro int SM_NONVOLATILE retry = 0; 392690792Sgshapiro#endif /* NAMED_BIND */ 392738032Speter char hbuf[MAXNAME + 1]; 392838032Speter 392938032Speter /* 393038032Speter ** See if we have already looked up this name. If so, just 393190792Sgshapiro ** return it (unless expired). 393238032Speter */ 393338032Speter 393490792Sgshapiro now = curtime(); 393538032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 393690792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 393790792Sgshapiro s->s_namecanon.nc_exp >= now) 393838032Speter { 393938032Speter if (tTd(9, 1)) 394090792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 394190792Sgshapiro name, 394290792Sgshapiro s->s_namecanon.nc_cname == NULL 394338032Speter ? "NULL" 394438032Speter : s->s_namecanon.nc_cname); 394538032Speter errno = s->s_namecanon.nc_errno; 394673188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 394738032Speter *statp = s->s_namecanon.nc_stat; 394838032Speter if (*statp == EX_TEMPFAIL) 394938032Speter { 395038032Speter CurEnv->e_status = "4.4.3"; 395138032Speter message("851 %s: Name server timeout", 395238032Speter shortenstring(name, 33)); 395338032Speter } 395438032Speter if (*statp != EX_OK) 395538032Speter return NULL; 395638032Speter if (s->s_namecanon.nc_cname == NULL) 395738032Speter { 3958132943Sgshapiro syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d", 395964562Sgshapiro name, 396064562Sgshapiro s->s_namecanon.nc_errno, 396164562Sgshapiro s->s_namecanon.nc_herrno); 396238032Speter return NULL; 396338032Speter } 396438032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 396538032Speter cp = map_rewrite(map, name, strlen(name), NULL); 396638032Speter else 396738032Speter cp = map_rewrite(map, 396838032Speter s->s_namecanon.nc_cname, 396938032Speter strlen(s->s_namecanon.nc_cname), 397038032Speter av); 397138032Speter return cp; 397238032Speter } 397338032Speter 397438032Speter /* 397538032Speter ** If we are running without a regular network connection (usually 397638032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 397738032Speter ** lookups because those could try to connect to a server. 397838032Speter */ 397938032Speter 398064562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 398164562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 398238032Speter { 398338032Speter if (tTd(9, 1)) 398490792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 398538032Speter *statp = EX_TEMPFAIL; 398638032Speter return NULL; 398738032Speter } 398838032Speter 398938032Speter /* 399038032Speter ** If first character is a bracket, then it is an address 399138032Speter ** lookup. Address is copied into a temporary buffer to 399238032Speter ** strip the brackets and to preserve name if address is 399338032Speter ** unknown. 399438032Speter */ 399538032Speter 399664562Sgshapiro if (tTd(9, 1)) 399790792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 399890792Sgshapiro#if NAMED_BIND 399990792Sgshapiro if (map->map_timeout > 0) 400090792Sgshapiro { 400190792Sgshapiro retrans = _res.retrans; 400290792Sgshapiro _res.retrans = map->map_timeout; 400390792Sgshapiro } 400490792Sgshapiro if (map->map_retry > 0) 400590792Sgshapiro { 400690792Sgshapiro retry = _res.retry; 400790792Sgshapiro _res.retry = map->map_retry; 400890792Sgshapiro } 400990792Sgshapiro#endif /* NAMED_BIND */ 401090792Sgshapiro 401190792Sgshapiro /* set default TTL */ 401290792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 401338032Speter if (*name != '[') 401438032Speter { 401590792Sgshapiro int ttl; 401690792Sgshapiro 4017168515Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof(hbuf)); 4018168515Sgshapiro if (getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl)) 401990792Sgshapiro { 402064562Sgshapiro ans = hbuf; 402190792Sgshapiro if (ttl > 0) 402290792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 402390792Sgshapiro SM_DEFAULT_TTL); 402490792Sgshapiro } 402564562Sgshapiro } 402664562Sgshapiro else 402764562Sgshapiro { 402864562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 402971345Sgshapiro { 403071345Sgshapiro if (tTd(9, 1)) 403190792Sgshapiro sm_dprintf("FAILED\n"); 403264562Sgshapiro return NULL; 403371345Sgshapiro } 403464562Sgshapiro *cp = '\0'; 403564562Sgshapiro 403664562Sgshapiro hp = NULL; 403790792Sgshapiro#if NETINET 403864562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 403964562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 404064562Sgshapiro INADDRSZ, AF_INET); 404190792Sgshapiro#endif /* NETINET */ 404290792Sgshapiro#if NETINET6 404364562Sgshapiro if (hp == NULL && 404490792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 404564562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 404664562Sgshapiro IN6ADDRSZ, AF_INET6); 404790792Sgshapiro#endif /* NETINET6 */ 404864562Sgshapiro *cp = ']'; 404964562Sgshapiro 405064562Sgshapiro if (hp != NULL) 405138032Speter { 405264562Sgshapiro /* found a match -- copy out */ 405390792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 405490792Sgshapiro#if NETINET6 405590792Sgshapiro if (ans == hp->h_name) 405690792Sgshapiro { 405790792Sgshapiro static char n[MAXNAME + 1]; 405890792Sgshapiro 405990792Sgshapiro /* hp->h_name is about to disappear */ 4060168515Sgshapiro (void) sm_strlcpy(n, ans, sizeof(n)); 406190792Sgshapiro ans = n; 406290792Sgshapiro } 406371345Sgshapiro freehostent(hp); 406471345Sgshapiro hp = NULL; 406590792Sgshapiro#endif /* NETINET6 */ 406638032Speter } 406764562Sgshapiro } 406890792Sgshapiro#if NAMED_BIND 406990792Sgshapiro if (map->map_timeout > 0) 407090792Sgshapiro _res.retrans = retrans; 407190792Sgshapiro if (map->map_retry > 0) 407290792Sgshapiro _res.retry = retry; 407390792Sgshapiro#endif /* NAMED_BIND */ 407438032Speter 407564562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 407638032Speter 407764562Sgshapiro /* Found an answer */ 407864562Sgshapiro if (ans != NULL) 407964562Sgshapiro { 408064562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 408190792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 408290792Sgshapiro sm_free(s->s_namecanon.nc_cname); 408390792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 408464562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 408564562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 408664562Sgshapiro else 408764562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 408871345Sgshapiro if (tTd(9, 1)) 408990792Sgshapiro sm_dprintf("FOUND %s\n", ans); 409064562Sgshapiro return cp; 409138032Speter } 409238032Speter 409364562Sgshapiro 409464562Sgshapiro /* No match found */ 409538032Speter s->s_namecanon.nc_errno = errno; 409690792Sgshapiro#if NAMED_BIND 409738032Speter s->s_namecanon.nc_herrno = h_errno; 409864562Sgshapiro if (tTd(9, 1)) 409990792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 410064562Sgshapiro switch (h_errno) 410138032Speter { 410264562Sgshapiro case TRY_AGAIN: 410364562Sgshapiro if (UseNameServer) 410464562Sgshapiro { 410564562Sgshapiro CurEnv->e_status = "4.4.3"; 410664562Sgshapiro message("851 %s: Name server timeout", 410764562Sgshapiro shortenstring(name, 33)); 410864562Sgshapiro } 410964562Sgshapiro *statp = EX_TEMPFAIL; 411064562Sgshapiro break; 411164562Sgshapiro 411264562Sgshapiro case HOST_NOT_FOUND: 411364562Sgshapiro case NO_DATA: 411464562Sgshapiro *statp = EX_NOHOST; 411564562Sgshapiro break; 411664562Sgshapiro 411764562Sgshapiro case NO_RECOVERY: 411864562Sgshapiro *statp = EX_SOFTWARE; 411964562Sgshapiro break; 412064562Sgshapiro 412164562Sgshapiro default: 412264562Sgshapiro *statp = EX_UNAVAILABLE; 412364562Sgshapiro break; 412438032Speter } 412590792Sgshapiro#else /* NAMED_BIND */ 412664562Sgshapiro if (tTd(9, 1)) 412790792Sgshapiro sm_dprintf("FAIL\n"); 412864562Sgshapiro *statp = EX_NOHOST; 412990792Sgshapiro#endif /* NAMED_BIND */ 413064562Sgshapiro s->s_namecanon.nc_stat = *statp; 413164562Sgshapiro return NULL; 413238032Speter} 413338032Speter/* 413490792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 413538032Speter** 413638032Speter** Parameters: 413790792Sgshapiro** map -- a pointer to this map. 413890792Sgshapiro** args -- argument string. 413938032Speter** 414038032Speter** Returns: 414190792Sgshapiro** true. 414238032Speter*/ 414338032Speter 414438032Speterbool 414538032Speterhost_map_init(map, args) 414638032Speter MAP *map; 414738032Speter char *args; 414838032Speter{ 414938032Speter register char *p = args; 415038032Speter 415138032Speter for (;;) 415238032Speter { 415338032Speter while (isascii(*p) && isspace(*p)) 415438032Speter p++; 415538032Speter if (*p != '-') 415638032Speter break; 415738032Speter switch (*++p) 415838032Speter { 415938032Speter case 'a': 416038032Speter map->map_app = ++p; 416138032Speter break; 416238032Speter 416338032Speter case 'T': 416438032Speter map->map_tapp = ++p; 416538032Speter break; 416638032Speter 416738032Speter case 'm': 416838032Speter map->map_mflags |= MF_MATCHONLY; 416938032Speter break; 417038032Speter 417138032Speter case 't': 417238032Speter map->map_mflags |= MF_NODEFER; 417338032Speter break; 417464562Sgshapiro 417564562Sgshapiro case 'S': /* only for consistency */ 417664562Sgshapiro map->map_spacesub = *++p; 417764562Sgshapiro break; 417864562Sgshapiro 417964562Sgshapiro case 'D': 418064562Sgshapiro map->map_mflags |= MF_DEFER; 418164562Sgshapiro break; 418290792Sgshapiro 418390792Sgshapiro case 'd': 418490792Sgshapiro { 418590792Sgshapiro char *h; 418690792Sgshapiro 418790792Sgshapiro while (isascii(*++p) && isspace(*p)) 418890792Sgshapiro continue; 418990792Sgshapiro h = strchr(p, ' '); 419090792Sgshapiro if (h != NULL) 419190792Sgshapiro *h = '\0'; 419290792Sgshapiro map->map_timeout = convtime(p, 's'); 419390792Sgshapiro if (h != NULL) 419490792Sgshapiro *h = ' '; 419590792Sgshapiro } 419690792Sgshapiro break; 419790792Sgshapiro 419890792Sgshapiro case 'r': 419990792Sgshapiro while (isascii(*++p) && isspace(*p)) 420090792Sgshapiro continue; 420190792Sgshapiro map->map_retry = atoi(p); 420290792Sgshapiro break; 420338032Speter } 420438032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 420538032Speter p++; 420638032Speter if (*p != '\0') 420738032Speter *p++ = '\0'; 420838032Speter } 420938032Speter if (map->map_app != NULL) 421038032Speter map->map_app = newstr(map->map_app); 421138032Speter if (map->map_tapp != NULL) 421238032Speter map->map_tapp = newstr(map->map_tapp); 421390792Sgshapiro return true; 421438032Speter} 421590792Sgshapiro 421664562Sgshapiro#if NETINET6 421764562Sgshapiro/* 421864562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 421964562Sgshapiro** 422064562Sgshapiro** Parameters: 422164562Sgshapiro** s6a -- a pointer to an in6_addr structure. 422264562Sgshapiro** dst -- buffer to store result in 422364562Sgshapiro** dst_len -- size of dst buffer 422464562Sgshapiro** 422564562Sgshapiro** Returns: 422664562Sgshapiro** A printable version of that structure. 422764562Sgshapiro*/ 422890792Sgshapiro 422964562Sgshapirochar * 423064562Sgshapiroanynet_ntop(s6a, dst, dst_len) 423164562Sgshapiro struct in6_addr *s6a; 423264562Sgshapiro char *dst; 423364562Sgshapiro size_t dst_len; 423464562Sgshapiro{ 423564562Sgshapiro register char *ap; 423664562Sgshapiro 423764562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 423864562Sgshapiro ap = (char *) inet_ntop(AF_INET, 423964562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 424064562Sgshapiro dst, dst_len); 424164562Sgshapiro else 424290792Sgshapiro { 424390792Sgshapiro char *d; 424490792Sgshapiro size_t sz; 424590792Sgshapiro 424690792Sgshapiro /* Save pointer to beginning of string */ 424790792Sgshapiro d = dst; 424890792Sgshapiro 424990792Sgshapiro /* Add IPv6: protocol tag */ 425090792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 425190792Sgshapiro if (sz >= dst_len) 425290792Sgshapiro return NULL; 425390792Sgshapiro dst += sz; 425490792Sgshapiro dst_len -= sz; 425564562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 425690792Sgshapiro 425790792Sgshapiro /* Restore pointer to beginning of string */ 425890792Sgshapiro if (ap != NULL) 425990792Sgshapiro ap = d; 426090792Sgshapiro } 426164562Sgshapiro return ap; 426264562Sgshapiro} 426390792Sgshapiro 426490792Sgshapiro/* 426590792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 426690792Sgshapiro** 426790792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 426890792Sgshapiro** 426990792Sgshapiro** Parameters: 427090792Sgshapiro** family -- address family 427190792Sgshapiro** src -- string 427290792Sgshapiro** dst -- destination address structure 427390792Sgshapiro** 427490792Sgshapiro** Returns: 427590792Sgshapiro** 1 if the address was valid 427690792Sgshapiro** 0 if the address wasn't parseable 427790792Sgshapiro** -1 if error 427890792Sgshapiro*/ 427990792Sgshapiro 428090792Sgshapiroint 428190792Sgshapiroanynet_pton(family, src, dst) 428290792Sgshapiro int family; 428390792Sgshapiro const char *src; 428490792Sgshapiro void *dst; 428590792Sgshapiro{ 428690792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 428790792Sgshapiro src += 5; 428890792Sgshapiro return inet_pton(family, src, dst); 428990792Sgshapiro} 429064562Sgshapiro#endif /* NETINET6 */ 429190792Sgshapiro/* 429238032Speter** ANYNET_NTOA -- convert a network address to printable form. 429338032Speter** 429438032Speter** Parameters: 429538032Speter** sap -- a pointer to a sockaddr structure. 429638032Speter** 429738032Speter** Returns: 429838032Speter** A printable version of that sockaddr. 429938032Speter*/ 430038032Speter 430138032Speter#ifdef USE_SOCK_STREAM 430238032Speter 430364562Sgshapiro# if NETLINK 430464562Sgshapiro# include <net/if_dl.h> 430564562Sgshapiro# endif /* NETLINK */ 430638032Speter 430738032Speterchar * 430838032Speteranynet_ntoa(sap) 430938032Speter register SOCKADDR *sap; 431038032Speter{ 431138032Speter register char *bp; 431238032Speter register char *ap; 431338032Speter int l; 431438032Speter static char buf[100]; 431538032Speter 431638032Speter /* check for null/zero family */ 431738032Speter if (sap == NULL) 431838032Speter return "NULLADDR"; 431938032Speter if (sap->sa.sa_family == 0) 432038032Speter return "0"; 432138032Speter 432238032Speter switch (sap->sa.sa_family) 432338032Speter { 432464562Sgshapiro# if NETUNIX 432538032Speter case AF_UNIX: 432664562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 4327168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[UNIX: %.64s]", 432890792Sgshapiro sap->sunix.sun_path); 432964562Sgshapiro else 4330168515Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof(buf)); 433138032Speter return buf; 433264562Sgshapiro# endif /* NETUNIX */ 433338032Speter 433464562Sgshapiro# if NETINET 433538032Speter case AF_INET: 433664562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 433764562Sgshapiro# endif /* NETINET */ 433838032Speter 433964562Sgshapiro# if NETINET6 434064562Sgshapiro case AF_INET6: 4341168515Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof(buf)); 434264562Sgshapiro if (ap != NULL) 434364562Sgshapiro return ap; 434464562Sgshapiro break; 434564562Sgshapiro# endif /* NETINET6 */ 434664562Sgshapiro 434764562Sgshapiro# if NETLINK 434838032Speter case AF_LINK: 4349168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[LINK: %s]", 435090792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 435138032Speter return buf; 435264562Sgshapiro# endif /* NETLINK */ 435338032Speter default: 435438032Speter /* this case is needed when nothing is #defined */ 435538032Speter /* in order to keep the switch syntactically correct */ 435638032Speter break; 435738032Speter } 435838032Speter 435938032Speter /* unknown family -- just dump bytes */ 4360168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Family %d: ", sap->sa.sa_family); 436138032Speter bp = &buf[strlen(buf)]; 436238032Speter ap = sap->sa.sa_data; 4363168515Sgshapiro for (l = sizeof(sap->sa.sa_data); --l >= 0; ) 436438032Speter { 436590792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 436690792Sgshapiro *ap++ & 0377); 436738032Speter bp += 3; 436838032Speter } 436938032Speter *--bp = '\0'; 437038032Speter return buf; 437138032Speter} 437290792Sgshapiro/* 437338032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 437438032Speter** 437538032Speter** Parameters: 437638032Speter** sap -- SOCKADDR pointer 437738032Speter** 437838032Speter** Returns: 437938032Speter** text representation of host name. 438038032Speter** 438138032Speter** Side Effects: 438238032Speter** none. 438338032Speter*/ 438438032Speter 438538032Speterchar * 438638032Speterhostnamebyanyaddr(sap) 438738032Speter register SOCKADDR *sap; 438838032Speter{ 438938032Speter register struct hostent *hp; 439064562Sgshapiro# if NAMED_BIND 439138032Speter int saveretry; 439264562Sgshapiro# endif /* NAMED_BIND */ 439364562Sgshapiro# if NETINET6 439464562Sgshapiro struct in6_addr in6_addr; 439564562Sgshapiro# endif /* NETINET6 */ 439638032Speter 439764562Sgshapiro# if NAMED_BIND 439838032Speter /* shorten name server timeout to avoid higher level timeouts */ 439938032Speter saveretry = _res.retry; 440064562Sgshapiro if (_res.retry * _res.retrans > 20) 440164562Sgshapiro _res.retry = 20 / _res.retrans; 440264562Sgshapiro# endif /* NAMED_BIND */ 440338032Speter 440438032Speter switch (sap->sa.sa_family) 440538032Speter { 440664562Sgshapiro# if NETINET 440738032Speter case AF_INET: 440838032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 440990792Sgshapiro INADDRSZ, AF_INET); 441038032Speter break; 441164562Sgshapiro# endif /* NETINET */ 441238032Speter 441364562Sgshapiro# if NETINET6 441464562Sgshapiro case AF_INET6: 441564562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 441690792Sgshapiro IN6ADDRSZ, AF_INET6); 441764562Sgshapiro break; 441864562Sgshapiro# endif /* NETINET6 */ 441964562Sgshapiro 442064562Sgshapiro# if NETISO 442138032Speter case AF_ISO: 442238032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 4423168515Sgshapiro sizeof(sap->siso.siso_addr), AF_ISO); 442438032Speter break; 442564562Sgshapiro# endif /* NETISO */ 442638032Speter 442764562Sgshapiro# if NETUNIX 442838032Speter case AF_UNIX: 442938032Speter hp = NULL; 443038032Speter break; 443164562Sgshapiro# endif /* NETUNIX */ 443238032Speter 443338032Speter default: 4434168515Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof(sap->sa.sa_data), 443590792Sgshapiro sap->sa.sa_family); 443638032Speter break; 443738032Speter } 443838032Speter 443964562Sgshapiro# if NAMED_BIND 444038032Speter _res.retry = saveretry; 444164562Sgshapiro# endif /* NAMED_BIND */ 444238032Speter 444364562Sgshapiro# if NETINET || NETINET6 444464562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 444564562Sgshapiro# if NETINET6 444664562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 444764562Sgshapiro# endif /* NETINET6 */ 444864562Sgshapiro# if NETINET 444964562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 445064562Sgshapiro# endif /* NETINET */ 445164562Sgshapiro ) 445271345Sgshapiro { 445371345Sgshapiro char *name; 445471345Sgshapiro 445590792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 445690792Sgshapiro# if NETINET6 445771345Sgshapiro if (name == hp->h_name) 445871345Sgshapiro { 445971345Sgshapiro static char n[MAXNAME + 1]; 446071345Sgshapiro 446171345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 4462168515Sgshapiro (void) sm_strlcpy(n, name, sizeof(n)); 446371345Sgshapiro name = n; 446471345Sgshapiro } 446571345Sgshapiro freehostent(hp); 446690792Sgshapiro# endif /* NETINET6 */ 446771345Sgshapiro return name; 446871345Sgshapiro } 446964562Sgshapiro# endif /* NETINET || NETINET6 */ 447071345Sgshapiro 447190792Sgshapiro# if NETINET6 447271345Sgshapiro if (hp != NULL) 447371345Sgshapiro { 447471345Sgshapiro freehostent(hp); 447571345Sgshapiro hp = NULL; 447671345Sgshapiro } 447790792Sgshapiro# endif /* NETINET6 */ 447871345Sgshapiro 447964562Sgshapiro# if NETUNIX 448064562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 448138032Speter return "localhost"; 448264562Sgshapiro# endif /* NETUNIX */ 448338032Speter { 448438032Speter static char buf[203]; 448538032Speter 4486168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[%.200s]", 448790792Sgshapiro anynet_ntoa(sap)); 448838032Speter return buf; 448938032Speter } 449038032Speter} 449164562Sgshapiro#endif /* USE_SOCK_STREAM */ 4492