daemon.c revision 157001
138032Speter/* 2157001Sgshapiro * Copyright (c) 1998-2006 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> 1538032Speter 16157001SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.665 2006/03/02 19:12:00 ca Exp $") 1764562Sgshapiro 1838032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 1938032Speter# define USE_SOCK_STREAM 1 2064562Sgshapiro#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */ 2138032Speter 2290792Sgshapiro#if defined(USE_SOCK_STREAM) 2364562Sgshapiro# if NETINET || NETINET6 2464562Sgshapiro# include <arpa/inet.h> 2564562Sgshapiro# endif /* NETINET || NETINET6 */ 2638032Speter# if NAMED_BIND 2738032Speter# ifndef NO_DATA 2838032Speter# define NO_DATA NO_ADDRESS 2964562Sgshapiro# endif /* ! NO_DATA */ 3064562Sgshapiro# endif /* NAMED_BIND */ 3190792Sgshapiro#endif /* defined(USE_SOCK_STREAM) */ 3238032Speter 3390792Sgshapiro#if STARTTLS 3490792Sgshapiro# include <openssl/rand.h> 3590792Sgshapiro#endif /* STARTTLS */ 3638032Speter 37157001Sgshapiro#include <sm/time.h> 3866494Sgshapiro 3990792Sgshapiro#if IP_SRCROUTE && NETINET 4090792Sgshapiro# include <netinet/in_systm.h> 4190792Sgshapiro# include <netinet/ip.h> 4290792Sgshapiro# if HAS_IN_H 4390792Sgshapiro# include <netinet/in.h> 4490792Sgshapiro# ifndef IPOPTION 4590792Sgshapiro# define IPOPTION ip_opts 4690792Sgshapiro# define IP_LIST ip_opts 4790792Sgshapiro# define IP_DST ip_dst 4890792Sgshapiro# endif /* ! IPOPTION */ 4990792Sgshapiro# else /* HAS_IN_H */ 5090792Sgshapiro# include <netinet/ip_var.h> 5190792Sgshapiro# ifndef IPOPTION 5290792Sgshapiro# define IPOPTION ipoption 5390792Sgshapiro# define IP_LIST ipopt_list 5490792Sgshapiro# define IP_DST ipopt_dst 5590792Sgshapiro# endif /* ! IPOPTION */ 5690792Sgshapiro# endif /* HAS_IN_H */ 5790792Sgshapiro#endif /* IP_SRCROUTE && NETINET */ 5838032Speter 5990792Sgshapiro#include <sm/fdset.h> 6038032Speter 6190792Sgshapiro/* structure to describe a daemon or a client */ 6264562Sgshapirostruct daemon 6364562Sgshapiro{ 6464562Sgshapiro int d_socket; /* fd for socket */ 6564562Sgshapiro SOCKADDR d_addr; /* socket for incoming */ 6690792Sgshapiro unsigned short d_port; /* port number */ 6764562Sgshapiro int d_listenqueue; /* size of listen queue */ 6864562Sgshapiro int d_tcprcvbufsize; /* size of TCP receive buffer */ 6964562Sgshapiro int d_tcpsndbufsize; /* size of TCP send buffer */ 7064562Sgshapiro time_t d_refuse_connections_until; 7164562Sgshapiro bool d_firsttime; 7264562Sgshapiro int d_socksize; 7364562Sgshapiro BITMAP256 d_flags; /* flags; see sendmail.h */ 7464562Sgshapiro char *d_mflags; /* flags for use in macro */ 7564562Sgshapiro char *d_name; /* user-supplied name */ 7690792Sgshapiro#if MILTER 7790792Sgshapiro char *d_inputfilterlist; 7890792Sgshapiro struct milter *d_inputfilters[MAXFILTERS]; 7990792Sgshapiro#endif /* MILTER */ 80147078Sgshapiro#if _FFR_SS_PER_DAEMON 81147078Sgshapiro int d_supersafe; 82147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 83147078Sgshapiro#if _FFR_DM_PER_DAEMON 84147078Sgshapiro int d_dm; /* DeliveryMode */ 85147078Sgshapiro#endif /* _FFR_DM_PER_DAEMON */ 8664562Sgshapiro}; 8764562Sgshapiro 8864562Sgshapirotypedef struct daemon DAEMON_T; 8964562Sgshapiro 90147078Sgshapiro#define SAFE_NOTSET (-1) /* SuperSafe (per daemon) option not set */ 91147078Sgshapiro/* see also sendmail.h: SuperSafe values */ 92147078Sgshapiro 93141858Sgshapirostatic void connecttimeout __P((int)); 9490792Sgshapirostatic int opendaemonsocket __P((DAEMON_T *, bool)); 9590792Sgshapirostatic unsigned short setupdaemon __P((SOCKADDR *)); 9690792Sgshapirostatic void getrequests_checkdiskspace __P((ENVELOPE *e)); 97141858Sgshapirostatic void setsockaddroptions __P((char *, DAEMON_T *)); 98141858Sgshapirostatic void printdaemonflags __P((DAEMON_T *)); 99141858Sgshapirostatic int addr_family __P((char *)); 100141858Sgshapirostatic int addrcmp __P((struct hostent *, char *, SOCKADDR *)); 101141858Sgshapirostatic void authtimeout __P((int)); 10264562Sgshapiro 10338032Speter/* 10438032Speter** DAEMON.C -- routines to use when running as a daemon. 10538032Speter** 10638032Speter** This entire file is highly dependent on the 4.2 BSD 10738032Speter** interprocess communication primitives. No attempt has 10838032Speter** been made to make this file portable to Version 7, 10938032Speter** Version 6, MPX files, etc. If you should try such a 11038032Speter** thing yourself, I recommend chucking the entire file 11138032Speter** and starting from scratch. Basic semantics are: 11238032Speter** 11338032Speter** getrequests(e) 11438032Speter** Opens a port and initiates a connection. 11538032Speter** Returns in a child. Must set InChannel and 11638032Speter** OutChannel appropriately. 11738032Speter** clrdaemon() 11838032Speter** Close any open files associated with getting 11938032Speter** the connection; this is used when running the queue, 12038032Speter** etc., to avoid having extra file descriptors during 12138032Speter** the queue run and to avoid confusing the network 12238032Speter** code (if it cares). 12390792Sgshapiro** makeconnection(host, port, mci, e, enough) 12438032Speter** Make a connection to the named host on the given 12590792Sgshapiro** port. Returns zero on success, else an exit status 12690792Sgshapiro** describing the error. 12738032Speter** host_map_lookup(map, hbuf, avp, pstat) 12838032Speter** Convert the entry in hbuf into a canonical form. 12938032Speter*/ 13064562Sgshapiro 13164562Sgshapirostatic DAEMON_T Daemons[MAXDAEMONS]; 13290792Sgshapirostatic int NDaemons = 0; /* actual number of daemons */ 13364562Sgshapiro 13490792Sgshapirostatic time_t NextDiskSpaceCheck = 0; 13564562Sgshapiro 13690792Sgshapiro/* 13738032Speter** GETREQUESTS -- open mail IPC port and get requests. 13838032Speter** 13938032Speter** Parameters: 14038032Speter** e -- the current envelope. 14138032Speter** 14238032Speter** Returns: 14364562Sgshapiro** pointer to flags. 14438032Speter** 14538032Speter** Side Effects: 14638032Speter** Waits until some interesting activity occurs. When 14738032Speter** it does, a child is created to process it, and the 14838032Speter** parent waits for completion. Return from this 14938032Speter** routine is always in the child. The file pointers 15038032Speter** "InChannel" and "OutChannel" should be set to point 15138032Speter** to the communication channel. 15290792Sgshapiro** May restart persistent queue runners if they have ended 15390792Sgshapiro** for some reason. 15438032Speter*/ 15538032Speter 15664562SgshapiroBITMAP256 * 15738032Spetergetrequests(e) 15838032Speter ENVELOPE *e; 15938032Speter{ 16038032Speter int t; 16164562Sgshapiro int idx, curdaemon = -1; 16264562Sgshapiro int i, olddaemon = 0; 16390792Sgshapiro#if XDEBUG 16438032Speter bool j_has_dot; 16590792Sgshapiro#endif /* XDEBUG */ 16642575Speter char status[MAXLINE]; 16764562Sgshapiro SOCKADDR sa; 16864562Sgshapiro SOCKADDR_LEN_T len = sizeof sa; 16994334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 17094334Sgshapiro time_t lastrun; 17194334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 17264562Sgshapiro# if NETUNIX 17342575Speter extern int ControlSocket; 17464562Sgshapiro# endif /* NETUNIX */ 17564562Sgshapiro extern ENVELOPE BlankEnvelope; 17690792Sgshapiro extern bool refuseconnections __P((char *, ENVELOPE *, int, bool)); 17738032Speter 17838032Speter 179125820Sgshapiro /* initialize data for function that generates queue ids */ 180125820Sgshapiro init_qid_alg(); 18190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 18238032Speter { 18364562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 18490792Sgshapiro Daemons[idx].d_firsttime = true; 18564562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 18638032Speter } 18771345Sgshapiro 18838032Speter /* 18938032Speter ** Try to actually open the connection. 19038032Speter */ 19138032Speter 19238032Speter if (tTd(15, 1)) 19364562Sgshapiro { 19490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 19571345Sgshapiro { 19690792Sgshapiro sm_dprintf("getrequests: daemon %s: port %d\n", 19790792Sgshapiro Daemons[idx].d_name, 19890792Sgshapiro ntohs(Daemons[idx].d_port)); 19971345Sgshapiro } 20064562Sgshapiro } 20138032Speter 20238032Speter /* get a socket for the SMTP connection */ 20390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 20490792Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true); 20538032Speter 20642575Speter if (opencontrolsocket() < 0) 20742575Speter sm_syslog(LOG_WARNING, NOQID, 20843730Speter "daemon could not open control socket %s: %s", 20990792Sgshapiro ControlSocketName, sm_errstring(errno)); 21042575Speter 21190792Sgshapiro /* If there are any queue runners released reapchild() co-ord's */ 21290792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 21338032Speter 21490792Sgshapiro /* write the pid to file, command line args to syslog */ 21564562Sgshapiro log_sendmail_pid(e); 21638032Speter 21790792Sgshapiro#if XDEBUG 21838032Speter { 21938032Speter char jbuf[MAXHOSTNAMELEN]; 22038032Speter 22138032Speter expand("\201j", jbuf, sizeof jbuf, e); 22238032Speter j_has_dot = strchr(jbuf, '.') != NULL; 22338032Speter } 22490792Sgshapiro#endif /* XDEBUG */ 22538032Speter 22642575Speter /* Add parent process as first item */ 227132943Sgshapiro proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL); 22842575Speter 22938032Speter if (tTd(15, 1)) 23064562Sgshapiro { 23190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 23290792Sgshapiro sm_dprintf("getrequests: daemon %s: %d\n", 23364562Sgshapiro Daemons[idx].d_name, 23464562Sgshapiro Daemons[idx].d_socket); 23564562Sgshapiro } 23638032Speter 23738032Speter for (;;) 23838032Speter { 23938032Speter register pid_t pid; 24038032Speter auto SOCKADDR_LEN_T lotherend; 24190792Sgshapiro bool timedout = false; 24290792Sgshapiro bool control = false; 24364562Sgshapiro int save_errno; 24438032Speter int pipefd[2]; 24590792Sgshapiro time_t now; 24690792Sgshapiro#if STARTTLS 24766494Sgshapiro long seed; 24890792Sgshapiro#endif /* STARTTLS */ 24938032Speter 25038032Speter /* see if we are rejecting connections */ 25190792Sgshapiro (void) sm_blocksignal(SIGALRM); 252120256Sgshapiro CHECK_RESTART; 25364562Sgshapiro 25490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 25571345Sgshapiro { 25690792Sgshapiro /* 25790792Sgshapiro ** XXX do this call outside the loop? 25890792Sgshapiro ** no: refuse_connections may sleep(). 25990792Sgshapiro */ 26071345Sgshapiro 26190792Sgshapiro now = curtime(); 26290792Sgshapiro if (now < Daemons[idx].d_refuse_connections_until) 26364562Sgshapiro continue; 26490792Sgshapiro if (bitnset(D_DISABLE, Daemons[idx].d_flags)) 26590792Sgshapiro continue; 26690792Sgshapiro if (refuseconnections(Daemons[idx].d_name, e, idx, 26790792Sgshapiro curdaemon == idx)) 26838032Speter { 26964562Sgshapiro if (Daemons[idx].d_socket >= 0) 27042575Speter { 27171345Sgshapiro /* close socket so peer fails quickly */ 27271345Sgshapiro (void) close(Daemons[idx].d_socket); 27371345Sgshapiro Daemons[idx].d_socket = -1; 27442575Speter } 27542575Speter 27642575Speter /* refuse connections for next 15 seconds */ 27790792Sgshapiro Daemons[idx].d_refuse_connections_until = now + 15; 27838032Speter } 27964562Sgshapiro else if (Daemons[idx].d_socket < 0 || 28064562Sgshapiro Daemons[idx].d_firsttime) 28142575Speter { 28290792Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel > 8) 28371345Sgshapiro sm_syslog(LOG_INFO, NOQID, 28471345Sgshapiro "accepting connections again for daemon %s", 28571345Sgshapiro Daemons[idx].d_name); 28664562Sgshapiro 28771345Sgshapiro /* arrange to (re)open the socket if needed */ 28890792Sgshapiro (void) opendaemonsocket(&Daemons[idx], false); 28990792Sgshapiro Daemons[idx].d_firsttime = false; 29042575Speter } 29138032Speter } 29238032Speter 29377349Sgshapiro /* May have been sleeping above, check again */ 294120256Sgshapiro CHECK_RESTART; 295132943Sgshapiro 29690792Sgshapiro getrequests_checkdiskspace(e); 29771345Sgshapiro 29890792Sgshapiro#if XDEBUG 29938032Speter /* check for disaster */ 30038032Speter { 30138032Speter char jbuf[MAXHOSTNAMELEN]; 30238032Speter 30338032Speter expand("\201j", jbuf, sizeof jbuf, e); 30438032Speter if (!wordinclass(jbuf, 'w')) 30538032Speter { 30638032Speter dumpstate("daemon lost $j"); 30738032Speter sm_syslog(LOG_ALERT, NOQID, 30864562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 30938032Speter abort(); 31038032Speter } 31138032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 31238032Speter { 31338032Speter dumpstate("daemon $j lost dot"); 31438032Speter sm_syslog(LOG_ALERT, NOQID, 31564562Sgshapiro "daemon process $j lost dot; see syslog"); 31638032Speter abort(); 31738032Speter } 31838032Speter } 31990792Sgshapiro#endif /* XDEBUG */ 32038032Speter 32190792Sgshapiro#if 0 32238032Speter /* 32338032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 32438032Speter ** fix the SVr4 problem. But it seems to have gone away, 32538032Speter ** so is it worth doing this? 32638032Speter */ 32738032Speter 32842575Speter if (DaemonSocket >= 0 && 32990792Sgshapiro SetNonBlocking(DaemonSocket, false) < 0) 33038032Speter log an error here; 33190792Sgshapiro#endif /* 0 */ 33290792Sgshapiro (void) sm_releasesignal(SIGALRM); 33364562Sgshapiro 33438032Speter for (;;) 33538032Speter { 33690792Sgshapiro bool setproc = false; 33742575Speter int highest = -1; 33838032Speter fd_set readfds; 33938032Speter struct timeval timeout; 34038032Speter 341120256Sgshapiro CHECK_RESTART; 34238032Speter FD_ZERO(&readfds); 34390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 34442575Speter { 34564562Sgshapiro /* wait for a connection */ 34664562Sgshapiro if (Daemons[idx].d_socket >= 0) 34764562Sgshapiro { 34871345Sgshapiro if (!setproc && 34971345Sgshapiro !bitnset(D_ETRNONLY, 35071345Sgshapiro Daemons[idx].d_flags)) 35164562Sgshapiro { 35290792Sgshapiro sm_setproctitle(true, e, 35364562Sgshapiro "accepting connections"); 35490792Sgshapiro setproc = true; 35564562Sgshapiro } 35664562Sgshapiro if (Daemons[idx].d_socket > highest) 35764562Sgshapiro highest = Daemons[idx].d_socket; 35890792Sgshapiro SM_FD_SET(Daemons[idx].d_socket, 35990792Sgshapiro &readfds); 36064562Sgshapiro } 36142575Speter } 36264562Sgshapiro 36390792Sgshapiro#if NETUNIX 36442575Speter if (ControlSocket >= 0) 36542575Speter { 36642575Speter if (ControlSocket > highest) 36742575Speter highest = ControlSocket; 36890792Sgshapiro SM_FD_SET(ControlSocket, &readfds); 36942575Speter } 37090792Sgshapiro#endif /* NETUNIX */ 37164562Sgshapiro 37277349Sgshapiro timeout.tv_sec = 5; 37338032Speter timeout.tv_usec = 0; 37438032Speter 37542575Speter t = select(highest + 1, FDSET_CAST &readfds, 37664562Sgshapiro NULL, NULL, &timeout); 37742575Speter 37877349Sgshapiro /* Did someone signal while waiting? */ 379120256Sgshapiro CHECK_RESTART; 38071345Sgshapiro 38190792Sgshapiro curdaemon = -1; 38290792Sgshapiro if (doqueuerun()) 38394334Sgshapiro { 38490792Sgshapiro (void) runqueue(true, false, false, false); 38594334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 38694334Sgshapiro lastrun = now; 38794334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 38894334Sgshapiro } 38994334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 390157001Sgshapiro else if (CheckQueueRunners > 0 && QueueIntvl > 0 && 391157001Sgshapiro lastrun + QueueIntvl + CheckQueueRunners < now) 39294334Sgshapiro { 39371345Sgshapiro 39494334Sgshapiro /* 39594334Sgshapiro ** set lastrun unconditionally to avoid 39694334Sgshapiro ** calling checkqueuerunner() all the time. 39794334Sgshapiro ** That's also why we currently ignore the 39894334Sgshapiro ** result of the function call. 39994334Sgshapiro */ 40094334Sgshapiro 40194334Sgshapiro (void) checkqueuerunner(); 40294334Sgshapiro lastrun = now; 40394334Sgshapiro } 40494334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 40594334Sgshapiro 40642575Speter if (t <= 0) 40742575Speter { 40890792Sgshapiro timedout = true; 40942575Speter break; 41042575Speter } 41138032Speter 41290792Sgshapiro control = false; 41338032Speter errno = 0; 41464562Sgshapiro 41564562Sgshapiro /* look "round-robin" for an active socket */ 41690792Sgshapiro if ((idx = olddaemon + 1) >= NDaemons) 41764562Sgshapiro idx = 0; 41890792Sgshapiro for (i = 0; i < NDaemons; i++) 41942575Speter { 42064562Sgshapiro if (Daemons[idx].d_socket >= 0 && 42190792Sgshapiro SM_FD_ISSET(Daemons[idx].d_socket, 42290792Sgshapiro &readfds)) 42364562Sgshapiro { 42464562Sgshapiro lotherend = Daemons[idx].d_socksize; 42573188Sgshapiro memset(&RealHostAddr, '\0', 42673188Sgshapiro sizeof RealHostAddr); 42764562Sgshapiro t = accept(Daemons[idx].d_socket, 42864562Sgshapiro (struct sockaddr *)&RealHostAddr, 42964562Sgshapiro &lotherend); 43073188Sgshapiro 43173188Sgshapiro /* 43273188Sgshapiro ** If remote side closes before 43373188Sgshapiro ** accept() finishes, sockaddr 43473188Sgshapiro ** might not be fully filled in. 43573188Sgshapiro */ 43673188Sgshapiro 43773188Sgshapiro if (t >= 0 && 43873188Sgshapiro (lotherend == 0 || 43973188Sgshapiro# ifdef BSD4_4_SOCKADDR 44073188Sgshapiro RealHostAddr.sa.sa_len == 0 || 44173188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 44273188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 44373188Sgshapiro { 44473188Sgshapiro (void) close(t); 44573188Sgshapiro t = -1; 44673188Sgshapiro errno = EINVAL; 44773188Sgshapiro } 44864562Sgshapiro olddaemon = curdaemon = idx; 44964562Sgshapiro break; 45064562Sgshapiro } 45190792Sgshapiro if (++idx >= NDaemons) 45264562Sgshapiro idx = 0; 45342575Speter } 45490792Sgshapiro#if NETUNIX 45564562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 45690792Sgshapiro SM_FD_ISSET(ControlSocket, &readfds)) 45742575Speter { 45842575Speter struct sockaddr_un sa_un; 45942575Speter 46042575Speter lotherend = sizeof sa_un; 46173188Sgshapiro memset(&sa_un, '\0', sizeof sa_un); 46242575Speter t = accept(ControlSocket, 46342575Speter (struct sockaddr *)&sa_un, 46442575Speter &lotherend); 46573188Sgshapiro 46673188Sgshapiro /* 46773188Sgshapiro ** If remote side closes before 46873188Sgshapiro ** accept() finishes, sockaddr 46973188Sgshapiro ** might not be fully filled in. 47073188Sgshapiro */ 47173188Sgshapiro 47273188Sgshapiro if (t >= 0 && 47373188Sgshapiro (lotherend == 0 || 47473188Sgshapiro# ifdef BSD4_4_SOCKADDR 47573188Sgshapiro sa_un.sun_len == 0 || 47673188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 47773188Sgshapiro sa_un.sun_family != AF_UNIX)) 47873188Sgshapiro { 47973188Sgshapiro (void) close(t); 48073188Sgshapiro t = -1; 48173188Sgshapiro errno = EINVAL; 48273188Sgshapiro } 48373188Sgshapiro if (t >= 0) 48490792Sgshapiro control = true; 48542575Speter } 48690792Sgshapiro#else /* NETUNIX */ 48771345Sgshapiro if (curdaemon == -1) 48871345Sgshapiro { 48971345Sgshapiro /* No daemon to service */ 49071345Sgshapiro continue; 49171345Sgshapiro } 49290792Sgshapiro#endif /* NETUNIX */ 49338032Speter if (t >= 0 || errno != EINTR) 49438032Speter break; 49538032Speter } 49642575Speter if (timedout) 49742575Speter { 49890792Sgshapiro timedout = false; 49942575Speter continue; 50042575Speter } 50164562Sgshapiro save_errno = errno; 50290792Sgshapiro (void) sm_blocksignal(SIGALRM); 50338032Speter if (t < 0) 50438032Speter { 50564562Sgshapiro errno = save_errno; 506132943Sgshapiro 507132943Sgshapiro /* let's ignore these temporary errors */ 508132943Sgshapiro if (save_errno == EINTR 509132943Sgshapiro#ifdef EAGAIN 510132943Sgshapiro || save_errno == EAGAIN 511132943Sgshapiro#endif /* EAGAIN */ 512132943Sgshapiro#ifdef ECONNABORTED 513132943Sgshapiro || save_errno == ECONNABORTED 514132943Sgshapiro#endif /* ECONNABORTED */ 515132943Sgshapiro#ifdef EWOULDBLOCK 516132943Sgshapiro || save_errno == EWOULDBLOCK 517132943Sgshapiro#endif /* EWOULDBLOCK */ 518132943Sgshapiro ) 519132943Sgshapiro continue; 520132943Sgshapiro 52138032Speter syserr("getrequests: accept"); 52238032Speter 52338032Speter /* arrange to re-open the socket next time around */ 52464562Sgshapiro (void) close(Daemons[curdaemon].d_socket); 52564562Sgshapiro Daemons[curdaemon].d_socket = -1; 52690792Sgshapiro#if SO_REUSEADDR_IS_BROKEN 52764562Sgshapiro /* 52864562Sgshapiro ** Give time for bound socket to be released. 52964562Sgshapiro ** This creates a denial-of-service if you can 53064562Sgshapiro ** force accept() to fail on affected systems. 53164562Sgshapiro */ 53264562Sgshapiro 53390792Sgshapiro Daemons[curdaemon].d_refuse_connections_until = curtime() + 15; 53490792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */ 53538032Speter continue; 53638032Speter } 53738032Speter 53864562Sgshapiro if (!control) 53964562Sgshapiro { 54064562Sgshapiro /* set some daemon related macros */ 54164562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 54264562Sgshapiro { 54364562Sgshapiro case AF_UNSPEC: 54490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54590792Sgshapiro macid("{daemon_family}"), "unspec"); 54664562Sgshapiro break; 54790792Sgshapiro#if _FFR_DAEMON_NETUNIX 54890792Sgshapiro# if NETUNIX 54990792Sgshapiro case AF_UNIX: 55090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55190792Sgshapiro macid("{daemon_family}"), "local"); 55290792Sgshapiro break; 55390792Sgshapiro# endif /* NETUNIX */ 55490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 55590792Sgshapiro#if NETINET 55664562Sgshapiro case AF_INET: 55790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55890792Sgshapiro macid("{daemon_family}"), "inet"); 55964562Sgshapiro break; 56090792Sgshapiro#endif /* NETINET */ 56190792Sgshapiro#if NETINET6 56264562Sgshapiro case AF_INET6: 56390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56490792Sgshapiro macid("{daemon_family}"), "inet6"); 56564562Sgshapiro break; 56690792Sgshapiro#endif /* NETINET6 */ 56790792Sgshapiro#if NETISO 56864562Sgshapiro case AF_ISO: 56990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 57090792Sgshapiro macid("{daemon_family}"), "iso"); 57164562Sgshapiro break; 57290792Sgshapiro#endif /* NETISO */ 57390792Sgshapiro#if NETNS 57464562Sgshapiro case AF_NS: 57590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 57690792Sgshapiro macid("{daemon_family}"), "ns"); 57764562Sgshapiro break; 57890792Sgshapiro#endif /* NETNS */ 57990792Sgshapiro#if NETX25 58064562Sgshapiro case AF_CCITT: 58190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 58290792Sgshapiro macid("{daemon_family}"), "x.25"); 58364562Sgshapiro break; 58490792Sgshapiro#endif /* NETX25 */ 58564562Sgshapiro } 58690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 58790792Sgshapiro macid("{daemon_name}"), 58890792Sgshapiro Daemons[curdaemon].d_name); 58964562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 59090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 59190792Sgshapiro macid("{daemon_flags}"), 59290792Sgshapiro Daemons[curdaemon].d_mflags); 59364562Sgshapiro else 59490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 59590792Sgshapiro macid("{daemon_flags}"), ""); 59664562Sgshapiro } 59764562Sgshapiro 59838032Speter /* 599132943Sgshapiro ** If connection rate is exceeded here, connection shall be 600132943Sgshapiro ** refused later by a new call after fork() by the 601132943Sgshapiro ** validate_connection() function. Closing the connection 602132943Sgshapiro ** at this point violates RFC 2821. 603132943Sgshapiro ** Do NOT remove this call, its side effects are needed. 604132943Sgshapiro */ 605132943Sgshapiro 606132943Sgshapiro connection_rate_check(&RealHostAddr, NULL); 607132943Sgshapiro 608132943Sgshapiro /* 60938032Speter ** Create a subprocess to process the mail. 61038032Speter */ 61138032Speter 61238032Speter if (tTd(15, 2)) 61390792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 61438032Speter 61538032Speter /* 61690792Sgshapiro ** Advance state of PRNG. 61790792Sgshapiro ** This is necessary because otherwise all child processes 61864562Sgshapiro ** will produce the same PRN sequence and hence the selection 61964562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 62064562Sgshapiro ** are not "really" random. 62164562Sgshapiro */ 62290792Sgshapiro#if STARTTLS 62390792Sgshapiro /* XXX get some better "random" data? */ 62466494Sgshapiro seed = get_random(); 62590792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 62690792Sgshapiro sizeof NextDiskSpaceCheck); 62790792Sgshapiro RAND_seed((void *) &now, sizeof now); 62866494Sgshapiro RAND_seed((void *) &seed, sizeof seed); 62990792Sgshapiro#else /* STARTTLS */ 63064562Sgshapiro (void) get_random(); 63190792Sgshapiro#endif /* STARTTLS */ 63264562Sgshapiro 63390792Sgshapiro#if NAMED_BIND 63464562Sgshapiro /* 635132943Sgshapiro ** Update MX records for FallbackMX. 63690792Sgshapiro ** Let's hope this is fast otherwise we screw up the 63790792Sgshapiro ** response time. 63890792Sgshapiro */ 63990792Sgshapiro 640132943Sgshapiro if (FallbackMX != NULL) 641132943Sgshapiro (void) getfallbackmxrr(FallbackMX); 64290792Sgshapiro#endif /* NAMED_BIND */ 64390792Sgshapiro 644110560Sgshapiro if (tTd(93, 100)) 645110560Sgshapiro { 646110560Sgshapiro /* don't fork, handle connection in this process */ 647110560Sgshapiro pid = 0; 64838032Speter pipefd[0] = pipefd[1] = -1; 649110560Sgshapiro } 650110560Sgshapiro else 651110560Sgshapiro { 652110560Sgshapiro /* 653110560Sgshapiro ** Create a pipe to keep the child from writing to 654110560Sgshapiro ** the socket until after the parent has closed 655110560Sgshapiro ** it. Otherwise the parent may hang if the child 656110560Sgshapiro ** has closed it first. 657110560Sgshapiro */ 65838032Speter 659110560Sgshapiro if (pipe(pipefd) < 0) 660110560Sgshapiro pipefd[0] = pipefd[1] = -1; 661110560Sgshapiro 662110560Sgshapiro (void) sm_blocksignal(SIGCHLD); 663110560Sgshapiro pid = fork(); 664110560Sgshapiro if (pid < 0) 66538032Speter { 666110560Sgshapiro syserr("daemon: cannot fork"); 667110560Sgshapiro if (pipefd[0] != -1) 668110560Sgshapiro { 669110560Sgshapiro (void) close(pipefd[0]); 670110560Sgshapiro (void) close(pipefd[1]); 671110560Sgshapiro } 672110560Sgshapiro (void) sm_releasesignal(SIGCHLD); 673110560Sgshapiro (void) sleep(10); 674110560Sgshapiro (void) close(t); 675110560Sgshapiro continue; 67638032Speter } 67738032Speter } 67890792Sgshapiro 67938032Speter if (pid == 0) 68038032Speter { 68138032Speter char *p; 68290792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 68338032Speter 68438032Speter /* 68538032Speter ** CHILD -- return to caller. 68638032Speter ** Collect verified idea of sending host. 68738032Speter ** Verify calling user id if possible here. 68838032Speter */ 68938032Speter 69077349Sgshapiro /* Reset global flags */ 69177349Sgshapiro RestartRequest = NULL; 69290792Sgshapiro RestartWorkGroup = false; 69377349Sgshapiro ShutdownRequest = NULL; 69477349Sgshapiro PendingSignal = 0; 69590792Sgshapiro CurrentPid = getpid(); 696132943Sgshapiro close_sendmail_pid(); 69777349Sgshapiro 69890792Sgshapiro (void) sm_releasesignal(SIGALRM); 69990792Sgshapiro (void) sm_releasesignal(SIGCHLD); 70090792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 70190792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 70290792Sgshapiro (void) sm_signal(SIGTERM, intsig); 70377349Sgshapiro 70490792Sgshapiro /* turn on profiling */ 70590792Sgshapiro /* SM_PROF(0); */ 70690792Sgshapiro 70790792Sgshapiro /* 70890792Sgshapiro ** Initialize exception stack and default exception 70990792Sgshapiro ** handler for child process. 71090792Sgshapiro */ 71190792Sgshapiro 71290792Sgshapiro sm_exc_newthread(fatal_error); 71390792Sgshapiro 71464562Sgshapiro if (!control) 71564562Sgshapiro { 71690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 71790792Sgshapiro macid("{daemon_addr}"), 71890792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 71990792Sgshapiro (void) sm_snprintf(status, sizeof status, "%d", 72064562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 72190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 72290792Sgshapiro macid("{daemon_port}"), status); 72364562Sgshapiro } 72464562Sgshapiro 72590792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 72664562Sgshapiro { 72764562Sgshapiro if (Daemons[idx].d_socket >= 0) 72864562Sgshapiro (void) close(Daemons[idx].d_socket); 72980785Sgshapiro Daemons[idx].d_socket = -1; 73064562Sgshapiro } 73142575Speter clrcontrol(); 73238032Speter 73364562Sgshapiro /* Avoid SMTP daemon actions if control command */ 73464562Sgshapiro if (control) 73564562Sgshapiro { 73664562Sgshapiro /* Add control socket process */ 73790792Sgshapiro proc_list_add(CurrentPid, 73890792Sgshapiro "console socket child", 739132943Sgshapiro PROC_CONTROL_CHILD, 0, -1, NULL); 74064562Sgshapiro } 74164562Sgshapiro else 74264562Sgshapiro { 74364562Sgshapiro proc_list_clear(); 74442575Speter 74590792Sgshapiro /* clean up background delivery children */ 74690792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 74790792Sgshapiro 74864562Sgshapiro /* Add parent process as first child item */ 74990792Sgshapiro proc_list_add(CurrentPid, "daemon child", 750132943Sgshapiro PROC_DAEMON_CHILD, 0, -1, NULL); 75138032Speter 75264562Sgshapiro /* don't schedule queue runs if ETRN */ 75364562Sgshapiro QueueIntvl = 0; 754147078Sgshapiro#if _FFR_SS_PER_DAEMON 755147078Sgshapiro if (Daemons[curdaemon].d_supersafe != 756147078Sgshapiro SAFE_NOTSET) 757147078Sgshapiro SuperSafe = Daemons[curdaemon].d_supersafe; 758147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 759147078Sgshapiro#if _FFR_DM_PER_DAEMON 760147078Sgshapiro if (Daemons[curdaemon].d_dm != DM_NOTSET) 761147078Sgshapiro set_delivery_mode( 762147078Sgshapiro Daemons[curdaemon].d_dm, e); 763147078Sgshapiro#endif /* _FFR_DM_PER_DAEMON */ 76438032Speter 76590792Sgshapiro sm_setproctitle(true, e, "startup with %s", 76664562Sgshapiro anynet_ntoa(&RealHostAddr)); 76764562Sgshapiro } 76864562Sgshapiro 76938032Speter if (pipefd[0] != -1) 77038032Speter { 77138032Speter auto char c; 77238032Speter 77338032Speter /* 77438032Speter ** Wait for the parent to close the write end 77538032Speter ** of the pipe, which we will see as an EOF. 77638032Speter ** This guarantees that we won't write to the 77738032Speter ** socket until after the parent has closed 77838032Speter ** the pipe. 77938032Speter */ 78038032Speter 78138032Speter /* close the write end of the pipe */ 78238032Speter (void) close(pipefd[1]); 78338032Speter 78438032Speter /* we shouldn't be interrupted, but ... */ 78538032Speter while (read(pipefd[0], &c, 1) < 0 && 78638032Speter errno == EINTR) 78738032Speter continue; 78838032Speter (void) close(pipefd[0]); 78938032Speter } 79038032Speter 79164562Sgshapiro /* control socket processing */ 79264562Sgshapiro if (control) 79364562Sgshapiro { 79464562Sgshapiro control_command(t, e); 79564562Sgshapiro /* NOTREACHED */ 79664562Sgshapiro exit(EX_SOFTWARE); 79764562Sgshapiro } 79864562Sgshapiro 79938032Speter /* determine host name */ 80038032Speter p = hostnamebyanyaddr(&RealHostAddr); 80190792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 80238032Speter p[MAXNAME] = '\0'; 80338032Speter RealHostName = newstr(p); 80464562Sgshapiro if (RealHostName[0] == '[') 80564562Sgshapiro { 80690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 80790792Sgshapiro macid("{client_resolve}"), 80890792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 80964562Sgshapiro } 81064562Sgshapiro else 811132943Sgshapiro { 81290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 813132943Sgshapiro macid("{client_resolve}"), "OK"); 814132943Sgshapiro } 81590792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 81694334Sgshapiro markstats(e, NULL, STATS_CONNECT); 81738032Speter 81890792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 81990792Sgshapiro SM_TIME_DEFAULT, 82090792Sgshapiro (void *) &t, 821132943Sgshapiro SM_IO_RDONLY_B, 82290792Sgshapiro NULL)) == NULL || 82338032Speter (t = dup(t)) < 0 || 82490792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 82590792Sgshapiro SM_TIME_DEFAULT, 82690792Sgshapiro (void *) &t, 827132943Sgshapiro SM_IO_WRONLY_B, 82890792Sgshapiro NULL)) == NULL) 82938032Speter { 83090792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 83190792Sgshapiro t); 83290792Sgshapiro finis(false, true, EX_OK); 83338032Speter } 83490792Sgshapiro sm_io_automode(inchannel, outchannel); 83538032Speter 83638032Speter InChannel = inchannel; 83738032Speter OutChannel = outchannel; 83890792Sgshapiro DisConnected = false; 83938032Speter 84090792Sgshapiro#if XLA 84138032Speter if (!xla_host_ok(RealHostName)) 84238032Speter { 84364562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 84490792Sgshapiro finis(false, true, EX_OK); 84538032Speter } 84690792Sgshapiro#endif /* XLA */ 84764562Sgshapiro /* find out name for interface of connection */ 84890792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 84990792Sgshapiro NULL), &sa.sa, &len) == 0) 85064562Sgshapiro { 85164562Sgshapiro p = hostnamebyanyaddr(&sa); 85264562Sgshapiro if (tTd(15, 9)) 85390792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 85490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 85590792Sgshapiro macid("{if_name}"), p); 85664562Sgshapiro 85790792Sgshapiro /* 85890792Sgshapiro ** Do this only if it is not the loopback 85990792Sgshapiro ** interface. 86090792Sgshapiro */ 86190792Sgshapiro 86264562Sgshapiro if (!isloopback(sa)) 86364562Sgshapiro { 86490792Sgshapiro char *addr; 86590792Sgshapiro char family[5]; 86690792Sgshapiro 86790792Sgshapiro addr = anynet_ntoa(&sa); 86890792Sgshapiro (void) sm_snprintf(family, 86990792Sgshapiro sizeof(family), 87090792Sgshapiro "%d", sa.sa.sa_family); 87190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87290792Sgshapiro A_TEMP, 87390792Sgshapiro macid("{if_addr}"), addr); 87490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87590792Sgshapiro A_TEMP, 87690792Sgshapiro macid("{if_family}"), family); 87764562Sgshapiro if (tTd(15, 7)) 87890792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 87990792Sgshapiro addr, family); 88064562Sgshapiro } 88164562Sgshapiro else 88264562Sgshapiro { 88390792Sgshapiro macdefine(&BlankEnvelope.e_macro, 88490792Sgshapiro A_PERM, 88590792Sgshapiro macid("{if_addr}"), NULL); 88690792Sgshapiro macdefine(&BlankEnvelope.e_macro, 88790792Sgshapiro A_PERM, 88890792Sgshapiro macid("{if_family}"), NULL); 88964562Sgshapiro } 89064562Sgshapiro } 89164562Sgshapiro else 89264562Sgshapiro { 89364562Sgshapiro if (tTd(15, 7)) 89490792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 89590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 89690792Sgshapiro macid("{if_name}"), NULL); 89790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 89890792Sgshapiro macid("{if_addr}"), NULL); 89990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 90090792Sgshapiro macid("{if_family}"), NULL); 90164562Sgshapiro } 90238032Speter break; 90338032Speter } 90438032Speter 90538032Speter /* parent -- keep track of children */ 90664562Sgshapiro if (control) 90764562Sgshapiro { 90890792Sgshapiro (void) sm_snprintf(status, sizeof status, 90990792Sgshapiro "control socket server child"); 910132943Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL); 91164562Sgshapiro } 91264562Sgshapiro else 91364562Sgshapiro { 91490792Sgshapiro (void) sm_snprintf(status, sizeof status, 91590792Sgshapiro "SMTP server child for %s", 91690792Sgshapiro anynet_ntoa(&RealHostAddr)); 917132943Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1, 918132943Sgshapiro &RealHostAddr); 91964562Sgshapiro } 92090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 92138032Speter 92238032Speter /* close the read end of the synchronization pipe */ 92338032Speter if (pipefd[0] != -1) 92464562Sgshapiro { 92538032Speter (void) close(pipefd[0]); 92664562Sgshapiro pipefd[0] = -1; 92764562Sgshapiro } 92838032Speter 92938032Speter /* close the port so that others will hang (for a while) */ 93038032Speter (void) close(t); 93138032Speter 93238032Speter /* release the child by closing the read end of the sync pipe */ 93338032Speter if (pipefd[1] != -1) 93464562Sgshapiro { 93538032Speter (void) close(pipefd[1]); 93664562Sgshapiro pipefd[1] = -1; 93764562Sgshapiro } 93838032Speter } 93990792Sgshapiro if (tTd(15, 2)) 94090792Sgshapiro sm_dprintf("getreq: returning\n"); 94164562Sgshapiro 94290792Sgshapiro#if MILTER 94390792Sgshapiro /* set the filters for this daemon */ 94490792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 94590792Sgshapiro { 94690792Sgshapiro for (i = 0; 947110560Sgshapiro (i < MAXFILTERS && 948110560Sgshapiro Daemons[curdaemon].d_inputfilters[i] != NULL); 94990792Sgshapiro i++) 95090792Sgshapiro { 95190792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 95290792Sgshapiro } 95390792Sgshapiro if (i < MAXFILTERS) 95490792Sgshapiro InputFilters[i] = NULL; 95590792Sgshapiro } 95690792Sgshapiro#endif /* MILTER */ 95764562Sgshapiro return &Daemons[curdaemon].d_flags; 95838032Speter} 95990792Sgshapiro 96090792Sgshapiro/* 96190792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 96290792Sgshapiro** 96390792Sgshapiro** Parameters: 96490792Sgshapiro** e -- envelope. 96590792Sgshapiro** 96690792Sgshapiro** Returns: 96790792Sgshapiro** none. 96890792Sgshapiro** 96990792Sgshapiro** Side Effects: 97090792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 97190792Sgshapiro*/ 97290792Sgshapiro 97390792Sgshapirostatic void 97490792Sgshapirogetrequests_checkdiskspace(e) 97590792Sgshapiro ENVELOPE *e; 97690792Sgshapiro{ 97790792Sgshapiro bool logged = false; 97890792Sgshapiro int idx; 97990792Sgshapiro time_t now; 98090792Sgshapiro 98190792Sgshapiro now = curtime(); 98290792Sgshapiro if (now < NextDiskSpaceCheck) 98390792Sgshapiro return; 98490792Sgshapiro 98590792Sgshapiro /* Check if there is available disk space in all queue groups. */ 98690792Sgshapiro if (!enoughdiskspace(0, NULL)) 98790792Sgshapiro { 98890792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 98990792Sgshapiro { 99090792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 99190792Sgshapiro continue; 99290792Sgshapiro 99390792Sgshapiro /* log only if not logged before */ 99490792Sgshapiro if (!logged) 99590792Sgshapiro { 99690792Sgshapiro if (LogLevel > 8) 99790792Sgshapiro sm_syslog(LOG_INFO, NOQID, 99890792Sgshapiro "rejecting new messages: min free: %ld", 99990792Sgshapiro MinBlocksFree); 100090792Sgshapiro sm_setproctitle(true, e, 100190792Sgshapiro "rejecting new messages: min free: %ld", 100290792Sgshapiro MinBlocksFree); 100390792Sgshapiro logged = true; 100490792Sgshapiro } 100590792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 100690792Sgshapiro } 100790792Sgshapiro } 100890792Sgshapiro else 100990792Sgshapiro { 101090792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 101190792Sgshapiro { 101290792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 101390792Sgshapiro continue; 101490792Sgshapiro 101590792Sgshapiro /* log only if not logged before */ 101690792Sgshapiro if (!logged) 101790792Sgshapiro { 101890792Sgshapiro if (LogLevel > 8) 101990792Sgshapiro sm_syslog(LOG_INFO, NOQID, 102090792Sgshapiro "accepting new messages (again)"); 102190792Sgshapiro logged = true; 102290792Sgshapiro } 102390792Sgshapiro 102490792Sgshapiro /* title will be set later */ 102590792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 102690792Sgshapiro } 102790792Sgshapiro } 102890792Sgshapiro 102990792Sgshapiro /* only check disk space once a minute */ 103090792Sgshapiro NextDiskSpaceCheck = now + 60; 103190792Sgshapiro} 103290792Sgshapiro 103390792Sgshapiro/* 103464562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 103538032Speter** 103664562Sgshapiro** Deals with setting all appropriate options. 103738032Speter** 103838032Speter** Parameters: 103964562Sgshapiro** d -- the structure for the daemon to open. 104038032Speter** firsttime -- set if this is the initial open. 104138032Speter** 104238032Speter** Returns: 104338032Speter** Size in bytes of the daemon socket addr. 104438032Speter** 104538032Speter** Side Effects: 104638032Speter** Leaves DaemonSocket set to the open socket. 104738032Speter** Exits if the socket cannot be created. 104838032Speter*/ 104938032Speter 105090792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 105138032Speter 105264562Sgshapirostatic int 105364562Sgshapiroopendaemonsocket(d, firsttime) 105490792Sgshapiro DAEMON_T *d; 105538032Speter bool firsttime; 105638032Speter{ 105738032Speter int on = 1; 105864562Sgshapiro int fdflags; 105964562Sgshapiro SOCKADDR_LEN_T socksize = 0; 106038032Speter int ntries = 0; 106164562Sgshapiro int save_errno; 106238032Speter 106338032Speter if (tTd(15, 2)) 106490792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 106538032Speter 106638032Speter do 106738032Speter { 106838032Speter if (ntries > 0) 106964562Sgshapiro (void) sleep(5); 107064562Sgshapiro if (firsttime || d->d_socket < 0) 107138032Speter { 107290792Sgshapiro#if _FFR_DAEMON_NETUNIX 107390792Sgshapiro# if NETUNIX 107490792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 107590792Sgshapiro { 107690792Sgshapiro int rval; 107790792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 107890792Sgshapiro 107990792Sgshapiro /* if not safe, don't use it */ 108090792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 108190792Sgshapiro RunAsUid, RunAsGid, 108290792Sgshapiro RunAsUserName, sff, 108390792Sgshapiro S_IRUSR|S_IWUSR, NULL); 108490792Sgshapiro if (rval != 0) 108590792Sgshapiro { 108690792Sgshapiro save_errno = errno; 108790792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 108890792Sgshapiro d->d_name, 108990792Sgshapiro d->d_addr.sunix.sun_path); 109090792Sgshapiro goto fail; 109190792Sgshapiro } 109290792Sgshapiro 109390792Sgshapiro /* Don't try to overtake an existing socket */ 109490792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 109590792Sgshapiro } 109690792Sgshapiro# endif /* NETUNIX */ 109790792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */ 109864562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 109964562Sgshapiro SOCK_STREAM, 0); 110064562Sgshapiro if (d->d_socket < 0) 110138032Speter { 110264562Sgshapiro save_errno = errno; 110390792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 110490792Sgshapiro d->d_name); 110590792Sgshapiro fail: 110690792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 110790792Sgshapiro (!transienterror(save_errno) || 110890792Sgshapiro ntries >= MAXOPENTRIES - 1)) 110990792Sgshapiro { 111090792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 111190792Sgshapiro d->d_name); 111290792Sgshapiro setbitn(D_DISABLE, d->d_flags); 111390792Sgshapiro d->d_socket = -1; 111490792Sgshapiro return -1; 111590792Sgshapiro } 111638032Speter severe: 111738032Speter if (LogLevel > 0) 111838032Speter sm_syslog(LOG_ALERT, NOQID, 111990792Sgshapiro "daemon %s: problem creating SMTP socket", 112090792Sgshapiro d->d_name); 112164562Sgshapiro d->d_socket = -1; 112238032Speter continue; 112338032Speter } 112438032Speter 1125110560Sgshapiro if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE) 1126110560Sgshapiro { 1127110560Sgshapiro save_errno = EINVAL; 1128110560Sgshapiro syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", 1129110560Sgshapiro d->d_name, d->d_socket); 1130110560Sgshapiro goto fail; 1131110560Sgshapiro } 1132110560Sgshapiro 113338032Speter /* turn on network debugging? */ 113438032Speter if (tTd(15, 101)) 113564562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 113638032Speter SO_DEBUG, (char *)&on, 113738032Speter sizeof on); 113838032Speter 113964562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 114038032Speter SO_REUSEADDR, (char *)&on, sizeof on); 114164562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 114238032Speter SO_KEEPALIVE, (char *)&on, sizeof on); 114338032Speter 114490792Sgshapiro#ifdef SO_RCVBUF 114564562Sgshapiro if (d->d_tcprcvbufsize > 0) 114638032Speter { 114764562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 114838032Speter SO_RCVBUF, 114964562Sgshapiro (char *) &d->d_tcprcvbufsize, 115064562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 115164562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 115238032Speter } 115390792Sgshapiro#endif /* SO_RCVBUF */ 115490792Sgshapiro#ifdef SO_SNDBUF 115564562Sgshapiro if (d->d_tcpsndbufsize > 0) 115664562Sgshapiro { 115764562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 115864562Sgshapiro SO_SNDBUF, 115964562Sgshapiro (char *) &d->d_tcpsndbufsize, 116064562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 116164562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 116264562Sgshapiro } 116390792Sgshapiro#endif /* SO_SNDBUF */ 116438032Speter 116564562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 116664562Sgshapiro fcntl(d->d_socket, F_SETFD, 116764562Sgshapiro fdflags | FD_CLOEXEC) == -1) 116838032Speter { 116964562Sgshapiro save_errno = errno; 117064562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 117164562Sgshapiro d->d_name, 117264562Sgshapiro fdflags == -1 ? "get" : "set", 117390792Sgshapiro sm_errstring(save_errno)); 117464562Sgshapiro (void) close(d->d_socket); 117564562Sgshapiro goto severe; 117664562Sgshapiro } 117764562Sgshapiro 117864562Sgshapiro switch (d->d_addr.sa.sa_family) 117964562Sgshapiro { 118090792Sgshapiro#if _FFR_DAEMON_NETUNIX 118190792Sgshapiro# ifdef NETUNIX 118290792Sgshapiro case AF_UNIX: 118390792Sgshapiro socksize = sizeof d->d_addr.sunix; 118490792Sgshapiro break; 118590792Sgshapiro# endif /* NETUNIX */ 118690792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 118790792Sgshapiro#if NETINET 118838032Speter case AF_INET: 118964562Sgshapiro socksize = sizeof d->d_addr.sin; 119038032Speter break; 119190792Sgshapiro#endif /* NETINET */ 119238032Speter 119390792Sgshapiro#if NETINET6 119464562Sgshapiro case AF_INET6: 119564562Sgshapiro socksize = sizeof d->d_addr.sin6; 119664562Sgshapiro break; 119790792Sgshapiro#endif /* NETINET6 */ 119864562Sgshapiro 119990792Sgshapiro#if NETISO 120038032Speter case AF_ISO: 120164562Sgshapiro socksize = sizeof d->d_addr.siso; 120238032Speter break; 120390792Sgshapiro#endif /* NETISO */ 120438032Speter 120538032Speter default: 120664562Sgshapiro socksize = sizeof d->d_addr; 120738032Speter break; 120838032Speter } 120938032Speter 121064562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 121138032Speter { 121238032Speter /* probably another daemon already */ 121364562Sgshapiro save_errno = errno; 121464562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 121564562Sgshapiro d->d_name); 121664562Sgshapiro (void) close(d->d_socket); 121790792Sgshapiro goto fail; 121838032Speter } 121938032Speter } 122064562Sgshapiro if (!firsttime && 122164562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 122238032Speter { 122364562Sgshapiro save_errno = errno; 122464562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 122564562Sgshapiro d->d_name); 122664562Sgshapiro (void) close(d->d_socket); 122738032Speter goto severe; 122838032Speter } 122938032Speter return socksize; 123064562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 123164562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 123264562Sgshapiro d->d_name); 123364562Sgshapiro /* NOTREACHED */ 123438032Speter return -1; /* avoid compiler warning on IRIX */ 123538032Speter} 123690792Sgshapiro/* 123764562Sgshapiro** SETUPDAEMON -- setup socket for daemon 123864562Sgshapiro** 123964562Sgshapiro** Parameters: 124064562Sgshapiro** daemonaddr -- socket for daemon 124164562Sgshapiro** 124264562Sgshapiro** Returns: 124364562Sgshapiro** port number on which daemon should run 124464562Sgshapiro** 124564562Sgshapiro*/ 124690792Sgshapiro 124790792Sgshapirostatic unsigned short 124864562Sgshapirosetupdaemon(daemonaddr) 124964562Sgshapiro SOCKADDR *daemonaddr; 125064562Sgshapiro{ 125190792Sgshapiro unsigned short port; 125264562Sgshapiro 125364562Sgshapiro /* 125464562Sgshapiro ** Set up the address for the mailer. 125564562Sgshapiro */ 125664562Sgshapiro 125764562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 125864562Sgshapiro { 125964562Sgshapiro memset(daemonaddr, '\0', sizeof *daemonaddr); 126090792Sgshapiro#if NETINET 126164562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 126290792Sgshapiro#endif /* NETINET */ 126364562Sgshapiro } 126464562Sgshapiro 126564562Sgshapiro switch (daemonaddr->sa.sa_family) 126664562Sgshapiro { 126790792Sgshapiro#if NETINET 126864562Sgshapiro case AF_INET: 126964562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 127064562Sgshapiro daemonaddr->sin.sin_addr.s_addr = INADDR_ANY; 127164562Sgshapiro port = daemonaddr->sin.sin_port; 127264562Sgshapiro break; 127390792Sgshapiro#endif /* NETINET */ 127464562Sgshapiro 127590792Sgshapiro#if NETINET6 127664562Sgshapiro case AF_INET6: 127764562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 127864562Sgshapiro daemonaddr->sin6.sin6_addr = in6addr_any; 127964562Sgshapiro port = daemonaddr->sin6.sin6_port; 128064562Sgshapiro break; 128190792Sgshapiro#endif /* NETINET6 */ 128264562Sgshapiro 128364562Sgshapiro default: 128464562Sgshapiro /* unknown protocol */ 128564562Sgshapiro port = 0; 128664562Sgshapiro break; 128764562Sgshapiro } 128864562Sgshapiro if (port == 0) 128964562Sgshapiro { 129090792Sgshapiro#ifdef NO_GETSERVBYNAME 129164562Sgshapiro port = htons(25); 129290792Sgshapiro#else /* NO_GETSERVBYNAME */ 129364562Sgshapiro { 129464562Sgshapiro register struct servent *sp; 129564562Sgshapiro 129664562Sgshapiro sp = getservbyname("smtp", "tcp"); 129764562Sgshapiro if (sp == NULL) 129864562Sgshapiro { 129964562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 130064562Sgshapiro port = htons(25); 130164562Sgshapiro } 130264562Sgshapiro else 130364562Sgshapiro port = sp->s_port; 130464562Sgshapiro } 130590792Sgshapiro#endif /* NO_GETSERVBYNAME */ 130664562Sgshapiro } 130764562Sgshapiro 130864562Sgshapiro switch (daemonaddr->sa.sa_family) 130964562Sgshapiro { 131090792Sgshapiro#if NETINET 131164562Sgshapiro case AF_INET: 131264562Sgshapiro daemonaddr->sin.sin_port = port; 131364562Sgshapiro break; 131490792Sgshapiro#endif /* NETINET */ 131564562Sgshapiro 131690792Sgshapiro#if NETINET6 131764562Sgshapiro case AF_INET6: 131864562Sgshapiro daemonaddr->sin6.sin6_port = port; 131964562Sgshapiro break; 132090792Sgshapiro#endif /* NETINET6 */ 132164562Sgshapiro 132264562Sgshapiro default: 132364562Sgshapiro /* unknown protocol */ 132464562Sgshapiro break; 132564562Sgshapiro } 132690792Sgshapiro return port; 132764562Sgshapiro} 132890792Sgshapiro/* 132938032Speter** CLRDAEMON -- reset the daemon connection 133038032Speter** 133138032Speter** Parameters: 133238032Speter** none. 133338032Speter** 133438032Speter** Returns: 133538032Speter** none. 133638032Speter** 133738032Speter** Side Effects: 133838032Speter** releases any resources used by the passive daemon. 133938032Speter*/ 134038032Speter 134138032Spetervoid 134238032Speterclrdaemon() 134338032Speter{ 134464562Sgshapiro int i; 134564562Sgshapiro 134690792Sgshapiro for (i = 0; i < NDaemons; i++) 134764562Sgshapiro { 134864562Sgshapiro if (Daemons[i].d_socket >= 0) 134964562Sgshapiro (void) close(Daemons[i].d_socket); 135064562Sgshapiro Daemons[i].d_socket = -1; 135164562Sgshapiro } 135238032Speter} 135390792Sgshapiro 135490792Sgshapiro/* 135590792Sgshapiro** GETMODIFIERS -- get modifier flags 135690792Sgshapiro** 135790792Sgshapiro** Parameters: 135890792Sgshapiro** v -- the modifiers (input text line). 135990792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 136090792Sgshapiro** 136190792Sgshapiro** Returns: 136290792Sgshapiro** (xallocat()ed) string representation of modifiers. 136390792Sgshapiro** 136490792Sgshapiro** Side Effects: 136590792Sgshapiro** fills in modifiers. 136690792Sgshapiro*/ 136790792Sgshapiro 136890792Sgshapirochar * 136990792Sgshapirogetmodifiers(v, modifiers) 137090792Sgshapiro char *v; 137190792Sgshapiro BITMAP256 modifiers; 137290792Sgshapiro{ 137390792Sgshapiro int l; 137490792Sgshapiro char *h, *f, *flags; 137590792Sgshapiro 137690792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 137790792Sgshapiro l = 3 * strlen(v) + 3; 137890792Sgshapiro 137990792Sgshapiro /* is someone joking? */ 138090792Sgshapiro if (l < 0 || l > 256) 138190792Sgshapiro { 138290792Sgshapiro if (LogLevel > 2) 138390792Sgshapiro sm_syslog(LOG_ERR, NOQID, 138490792Sgshapiro "getmodifiers too long, ignored"); 138590792Sgshapiro return NULL; 138690792Sgshapiro } 138790792Sgshapiro flags = xalloc(l); 138890792Sgshapiro f = flags; 138990792Sgshapiro clrbitmap(modifiers); 139090792Sgshapiro for (h = v; *h != '\0'; h++) 139190792Sgshapiro { 139290792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 139390792Sgshapiro { 139490792Sgshapiro setbitn(*h, modifiers); 139590792Sgshapiro if (flags != f) 139690792Sgshapiro *flags++ = ' '; 139790792Sgshapiro *flags++ = *h; 139890792Sgshapiro if (isupper(*h)) 139990792Sgshapiro *flags++ = *h; 140090792Sgshapiro } 140190792Sgshapiro } 140290792Sgshapiro *flags++ = '\0'; 140390792Sgshapiro return f; 140490792Sgshapiro} 140590792Sgshapiro 140690792Sgshapiro/* 140790792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 140890792Sgshapiro** 140990792Sgshapiro** Parameters: 141090792Sgshapiro** flag -- the flag to test. 141190792Sgshapiro** 141290792Sgshapiro** Returns: 141390792Sgshapiro** true iff all daemons have set flag. 141490792Sgshapiro*/ 141590792Sgshapiro 141690792Sgshapirobool 141790792Sgshapirochkdaemonmodifiers(flag) 141890792Sgshapiro int flag; 141990792Sgshapiro{ 142090792Sgshapiro int i; 142190792Sgshapiro 142290792Sgshapiro for (i = 0; i < NDaemons; i++) 142390792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 142490792Sgshapiro return false; 142590792Sgshapiro return true; 142690792Sgshapiro} 142790792Sgshapiro 142890792Sgshapiro/* 142964562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 143038032Speter** 143138032Speter** Parameters: 143238032Speter** p -- the options line. 143364562Sgshapiro** d -- the daemon structure to fill in. 143438032Speter** 143538032Speter** Returns: 143638032Speter** none. 143738032Speter*/ 143838032Speter 143964562Sgshapirostatic void 144064562Sgshapirosetsockaddroptions(p, d) 1441141858Sgshapiro char *p; 144290792Sgshapiro DAEMON_T *d; 144338032Speter{ 144490792Sgshapiro#if NETISO 144571345Sgshapiro short portno; 144690792Sgshapiro#endif /* NETISO */ 144771345Sgshapiro char *port = NULL; 144871345Sgshapiro char *addr = NULL; 144938032Speter 145090792Sgshapiro#if NETINET 145164562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 145264562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 145390792Sgshapiro#endif /* NETINET */ 1454157001Sgshapiro#if _FFR_SS_PER_DAEMON 1455157001Sgshapiro d->d_supersafe = SAFE_NOTSET; 1456157001Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1457157001Sgshapiro#if _FFR_DM_PER_DAEMON 1458157001Sgshapiro d->d_dm = DM_NOTSET; 1459157001Sgshapiro#endif /* _FFR_DM_PER_DAEMON */ 146064562Sgshapiro 146138032Speter while (p != NULL) 146238032Speter { 146338032Speter register char *f; 146438032Speter register char *v; 146538032Speter 146638032Speter while (isascii(*p) && isspace(*p)) 146738032Speter p++; 146838032Speter if (*p == '\0') 146938032Speter break; 147038032Speter f = p; 147138032Speter p = strchr(p, ','); 147238032Speter if (p != NULL) 147338032Speter *p++ = '\0'; 147438032Speter v = strchr(f, '='); 147538032Speter if (v == NULL) 147638032Speter continue; 147738032Speter while (isascii(*++v) && isspace(*v)) 147838032Speter continue; 147938032Speter if (isascii(*f) && islower(*f)) 148038032Speter *f = toupper(*f); 148138032Speter 148238032Speter switch (*f) 148338032Speter { 1484147078Sgshapiro case 'A': /* address */ 1485147078Sgshapiro addr = v; 1486147078Sgshapiro break; 1487147078Sgshapiro 1488147078Sgshapiro#if _FFR_DM_PER_DAEMON 1489147078Sgshapiro case 'D': /* DeliveryMode */ 1490147078Sgshapiro switch (*v) 1491147078Sgshapiro { 1492147078Sgshapiro case SM_QUEUE: 1493147078Sgshapiro case SM_DEFER: 1494147078Sgshapiro case SM_DELIVER: 1495157001Sgshapiro case SM_FORK: 1496147078Sgshapiro d->d_dm = *v; 1497147078Sgshapiro break; 1498147078Sgshapiro default: 1499147078Sgshapiro syserr("554 5.3.5 Unknown delivery mode %c", 1500147078Sgshapiro *v); 1501147078Sgshapiro break; 1502147078Sgshapiro } 1503147078Sgshapiro break; 1504147078Sgshapiro#endif /* _FFR_DM_PER_DAEMON */ 1505147078Sgshapiro 150638032Speter case 'F': /* address family */ 150738032Speter if (isascii(*v) && isdigit(*v)) 150864562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 150990792Sgshapiro#if _FFR_DAEMON_NETUNIX 151090792Sgshapiro# ifdef NETUNIX 151190792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 151290792Sgshapiro sm_strcasecmp(v, "local") == 0) 151390792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 151490792Sgshapiro# endif /* NETUNIX */ 151590792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 151690792Sgshapiro#if NETINET 151790792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 151864562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 151990792Sgshapiro#endif /* NETINET */ 152090792Sgshapiro#if NETINET6 152190792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 152264562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 152390792Sgshapiro#endif /* NETINET6 */ 152490792Sgshapiro#if NETISO 152590792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 152664562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 152790792Sgshapiro#endif /* NETISO */ 152890792Sgshapiro#if NETNS 152990792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 153064562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 153190792Sgshapiro#endif /* NETNS */ 153290792Sgshapiro#if NETX25 153390792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 153464562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 153590792Sgshapiro#endif /* NETX25 */ 153638032Speter else 153764562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 153864562Sgshapiro v); 153938032Speter break; 154038032Speter 154190792Sgshapiro#if MILTER 154290792Sgshapiro case 'I': 154390792Sgshapiro d->d_inputfilterlist = v; 154490792Sgshapiro break; 154590792Sgshapiro#endif /* MILTER */ 154690792Sgshapiro 154738032Speter case 'L': /* listen queue size */ 154864562Sgshapiro d->d_listenqueue = atoi(v); 154938032Speter break; 155038032Speter 155164562Sgshapiro case 'M': /* modifiers (flags) */ 155290792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 155364562Sgshapiro break; 155464562Sgshapiro 1555147078Sgshapiro case 'N': /* name */ 1556147078Sgshapiro d->d_name = v; 155738032Speter break; 155838032Speter 1559147078Sgshapiro case 'P': /* port */ 1560147078Sgshapiro port = v; 1561147078Sgshapiro break; 1562147078Sgshapiro 156338032Speter case 'R': /* receive buffer size */ 156464562Sgshapiro d->d_tcprcvbufsize = atoi(v); 156538032Speter break; 156638032Speter 1567147078Sgshapiro case 'S': /* send buffer size */ 1568147078Sgshapiro d->d_tcpsndbufsize = atoi(v); 156964562Sgshapiro break; 157064562Sgshapiro 1571147078Sgshapiro#if _FFR_SS_PER_DAEMON 1572147078Sgshapiro case 'T': /* SuperSafe */ 1573147078Sgshapiro if (tolower(*v) == 'i') 1574147078Sgshapiro d->d_supersafe = SAFE_INTERACTIVE; 1575147078Sgshapiro else if (tolower(*v) == 'p') 1576147078Sgshapiro# if MILTER 1577147078Sgshapiro d->d_supersafe = SAFE_REALLY_POSTMILTER; 1578147078Sgshapiro# else /* MILTER */ 1579147078Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1580147078Sgshapiro "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 1581147078Sgshapiro# endif /* MILTER */ 1582147078Sgshapiro else 1583147078Sgshapiro d->d_supersafe = atobool(v) ? SAFE_REALLY 1584147078Sgshapiro : SAFE_NO; 1585147078Sgshapiro break; 1586147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1587147078Sgshapiro 158838032Speter default: 158964562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 159064562Sgshapiro f); 159138032Speter } 159238032Speter } 159371345Sgshapiro 159471345Sgshapiro /* Check addr and port after finding family */ 159571345Sgshapiro if (addr != NULL) 159671345Sgshapiro { 159771345Sgshapiro switch (d->d_addr.sa.sa_family) 159871345Sgshapiro { 159990792Sgshapiro#if _FFR_DAEMON_NETUNIX 160090792Sgshapiro# if NETUNIX 160190792Sgshapiro case AF_UNIX: 160290792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 160390792Sgshapiro { 160490792Sgshapiro errno = ENAMETOOLONG; 160590792Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %d", 160690792Sgshapiro addr, sizeof(d->d_addr.sunix.sun_path)); 160790792Sgshapiro break; 160890792Sgshapiro } 160990792Sgshapiro 161090792Sgshapiro /* file safety check done in opendaemonsocket() */ 161190792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 161290792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 161390792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 161490792Sgshapiro addr, 161590792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 161690792Sgshapiro break; 161790792Sgshapiro# endif /* NETUNIX */ 161890792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 161990792Sgshapiro#if NETINET 162071345Sgshapiro case AF_INET: 162171345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 162290792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 162390792Sgshapiro == INADDR_NONE)) 162471345Sgshapiro { 162571345Sgshapiro register struct hostent *hp; 162671345Sgshapiro 162771345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 162871345Sgshapiro if (hp == NULL) 162971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 163071345Sgshapiro addr); 163171345Sgshapiro else 163271345Sgshapiro { 163371345Sgshapiro while (*(hp->h_addr_list) != NULL && 163471345Sgshapiro hp->h_addrtype != AF_INET) 163571345Sgshapiro hp->h_addr_list++; 163671345Sgshapiro if (*(hp->h_addr_list) == NULL) 163771345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 163871345Sgshapiro addr); 163971345Sgshapiro else 164071345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 164171345Sgshapiro *(hp->h_addr_list), 164271345Sgshapiro INADDRSZ); 164390792Sgshapiro# if NETINET6 164471345Sgshapiro freehostent(hp); 164571345Sgshapiro hp = NULL; 164690792Sgshapiro# endif /* NETINET6 */ 164771345Sgshapiro } 164871345Sgshapiro } 164971345Sgshapiro break; 165090792Sgshapiro#endif /* NETINET */ 165171345Sgshapiro 165290792Sgshapiro#if NETINET6 165371345Sgshapiro case AF_INET6: 165490792Sgshapiro if (anynet_pton(AF_INET6, addr, 165590792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 165671345Sgshapiro { 165771345Sgshapiro register struct hostent *hp; 165871345Sgshapiro 165971345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 166071345Sgshapiro if (hp == NULL) 166171345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 166271345Sgshapiro addr); 166371345Sgshapiro else 166471345Sgshapiro { 166571345Sgshapiro while (*(hp->h_addr_list) != NULL && 166671345Sgshapiro hp->h_addrtype != AF_INET6) 166771345Sgshapiro hp->h_addr_list++; 166871345Sgshapiro if (*(hp->h_addr_list) == NULL) 166971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 167071345Sgshapiro addr); 167171345Sgshapiro else 167271345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 167371345Sgshapiro *(hp->h_addr_list), 167471345Sgshapiro IN6ADDRSZ); 167571345Sgshapiro freehostent(hp); 167671345Sgshapiro hp = NULL; 167771345Sgshapiro } 167871345Sgshapiro } 167971345Sgshapiro break; 168090792Sgshapiro#endif /* NETINET6 */ 168171345Sgshapiro 168271345Sgshapiro default: 168371345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 168471345Sgshapiro d->d_addr.sa.sa_family); 168571345Sgshapiro break; 168671345Sgshapiro } 168771345Sgshapiro } 168871345Sgshapiro 168971345Sgshapiro if (port != NULL) 169071345Sgshapiro { 169171345Sgshapiro switch (d->d_addr.sa.sa_family) 169271345Sgshapiro { 169390792Sgshapiro#if NETINET 169471345Sgshapiro case AF_INET: 169571345Sgshapiro if (isascii(*port) && isdigit(*port)) 169690792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 169790792Sgshapiro atoi((const char *) port)); 169871345Sgshapiro else 169971345Sgshapiro { 170090792Sgshapiro# ifdef NO_GETSERVBYNAME 170171345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 170271345Sgshapiro port); 170390792Sgshapiro# else /* NO_GETSERVBYNAME */ 170471345Sgshapiro register struct servent *sp; 170571345Sgshapiro 170671345Sgshapiro sp = getservbyname(port, "tcp"); 170771345Sgshapiro if (sp == NULL) 170871345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 170971345Sgshapiro port); 171071345Sgshapiro else 171171345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 171290792Sgshapiro# endif /* NO_GETSERVBYNAME */ 171371345Sgshapiro } 171471345Sgshapiro break; 171590792Sgshapiro#endif /* NETINET */ 171671345Sgshapiro 171790792Sgshapiro#if NETINET6 171871345Sgshapiro case AF_INET6: 171971345Sgshapiro if (isascii(*port) && isdigit(*port)) 172090792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 172190792Sgshapiro atoi(port)); 172271345Sgshapiro else 172371345Sgshapiro { 172490792Sgshapiro# ifdef NO_GETSERVBYNAME 172571345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 172671345Sgshapiro port); 172790792Sgshapiro# else /* NO_GETSERVBYNAME */ 172871345Sgshapiro register struct servent *sp; 172971345Sgshapiro 173071345Sgshapiro sp = getservbyname(port, "tcp"); 173171345Sgshapiro if (sp == NULL) 173271345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 173371345Sgshapiro port); 173471345Sgshapiro else 173571345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 173690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 173771345Sgshapiro } 173871345Sgshapiro break; 173990792Sgshapiro#endif /* NETINET6 */ 174071345Sgshapiro 174190792Sgshapiro#if NETISO 174271345Sgshapiro case AF_ISO: 174371345Sgshapiro /* assume two byte transport selector */ 174471345Sgshapiro if (isascii(*port) && isdigit(*port)) 174590792Sgshapiro portno = htons((unsigned short) atoi(port)); 174671345Sgshapiro else 174771345Sgshapiro { 174890792Sgshapiro# ifdef NO_GETSERVBYNAME 174971345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 175071345Sgshapiro port); 175190792Sgshapiro# else /* NO_GETSERVBYNAME */ 175271345Sgshapiro register struct servent *sp; 175371345Sgshapiro 175471345Sgshapiro sp = getservbyname(port, "tcp"); 175571345Sgshapiro if (sp == NULL) 175671345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 175771345Sgshapiro port); 175871345Sgshapiro else 175971345Sgshapiro portno = sp->s_port; 176090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 176171345Sgshapiro } 176271345Sgshapiro memmove(TSEL(&d->d_addr.siso), 176371345Sgshapiro (char *) &portno, 2); 176471345Sgshapiro break; 176590792Sgshapiro#endif /* NETISO */ 176671345Sgshapiro 176771345Sgshapiro default: 176871345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 176971345Sgshapiro d->d_addr.sa.sa_family); 177071345Sgshapiro break; 177171345Sgshapiro } 177271345Sgshapiro } 177338032Speter} 177490792Sgshapiro/* 177564562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 177638032Speter** 177738032Speter** Parameters: 177864562Sgshapiro** p -- the options line. 177964562Sgshapiro** 178064562Sgshapiro** Returns: 178190792Sgshapiro** true if successful, false otherwise. 178290792Sgshapiro** 178390792Sgshapiro** Side Effects: 178490792Sgshapiro** increments number of daemons. 178564562Sgshapiro*/ 178664562Sgshapiro 178790792Sgshapiro#define DEF_LISTENQUEUE 10 178890792Sgshapiro 178998841Sgshapirostruct dflags 179098841Sgshapiro{ 179198841Sgshapiro char *d_name; 179298841Sgshapiro int d_flag; 179398841Sgshapiro}; 179498841Sgshapiro 179598841Sgshapirostatic struct dflags DaemonFlags[] = 179698841Sgshapiro{ 179798841Sgshapiro { "AUTHREQ", D_AUTHREQ }, 179898841Sgshapiro { "BINDIF", D_BINDIF }, 179998841Sgshapiro { "CANONREQ", D_CANONREQ }, 180098841Sgshapiro { "IFNHELO", D_IFNHELO }, 180198841Sgshapiro { "FQMAIL", D_FQMAIL }, 180298841Sgshapiro { "FQRCPT", D_FQRCPT }, 180398841Sgshapiro { "SMTPS", D_SMTPS }, 180498841Sgshapiro { "UNQUALOK", D_UNQUALOK }, 180598841Sgshapiro { "NOAUTH", D_NOAUTH }, 180698841Sgshapiro { "NOCANON", D_NOCANON }, 180798841Sgshapiro { "NOETRN", D_NOETRN }, 180898841Sgshapiro { "NOTLS", D_NOTLS }, 180998841Sgshapiro { "ETRNONLY", D_ETRNONLY }, 181098841Sgshapiro { "OPTIONAL", D_OPTIONAL }, 181198841Sgshapiro { "DISABLE", D_DISABLE }, 181298841Sgshapiro { "ISSET", D_ISSET }, 181398841Sgshapiro { NULL, 0 } 181498841Sgshapiro}; 181598841Sgshapiro 181698841Sgshapirostatic void 181798841Sgshapiroprintdaemonflags(d) 181898841Sgshapiro DAEMON_T *d; 181998841Sgshapiro{ 182098841Sgshapiro register struct dflags *df; 182198841Sgshapiro bool first = true; 182298841Sgshapiro 182398841Sgshapiro for (df = DaemonFlags; df->d_name != NULL; df++) 182498841Sgshapiro { 182598841Sgshapiro if (!bitnset(df->d_flag, d->d_flags)) 182698841Sgshapiro continue; 182798841Sgshapiro if (first) 1828132943Sgshapiro sm_dprintf("<%s", df->d_name); 182998841Sgshapiro else 1830132943Sgshapiro sm_dprintf(",%s", df->d_name); 183198841Sgshapiro first = false; 183298841Sgshapiro } 183398841Sgshapiro if (!first) 1834132943Sgshapiro sm_dprintf(">"); 183598841Sgshapiro} 183698841Sgshapiro 183764562Sgshapirobool 183864562Sgshapirosetdaemonoptions(p) 183964562Sgshapiro register char *p; 184064562Sgshapiro{ 184190792Sgshapiro if (NDaemons >= MAXDAEMONS) 184290792Sgshapiro return false; 184390792Sgshapiro Daemons[NDaemons].d_socket = -1; 184490792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 184590792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 184690792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 184764562Sgshapiro 184890792Sgshapiro#if MILTER 184990792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 185090792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 185190792Sgshapiro#endif /* MILTER */ 185290792Sgshapiro 185390792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 185490792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 185564562Sgshapiro else 185664562Sgshapiro { 185764562Sgshapiro char num[30]; 185864562Sgshapiro 185990792Sgshapiro (void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons); 186090792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 186164562Sgshapiro } 186264562Sgshapiro 186364562Sgshapiro if (tTd(37, 1)) 186464562Sgshapiro { 186590792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 186698841Sgshapiro printdaemonflags(&Daemons[NDaemons]); 186790792Sgshapiro sm_dprintf("\n"); 186864562Sgshapiro } 186990792Sgshapiro ++NDaemons; 187090792Sgshapiro return true; 187164562Sgshapiro} 187290792Sgshapiro/* 187364562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 187464562Sgshapiro** 187564562Sgshapiro** Parameters: 187664562Sgshapiro** none 187764562Sgshapiro** 187864562Sgshapiro** Returns: 187964562Sgshapiro** none 188064562Sgshapiro** 188164562Sgshapiro** Side Effects: 188264562Sgshapiro** initializes structure for one daemon. 188364562Sgshapiro*/ 188490792Sgshapiro 188564562Sgshapirovoid 188664562Sgshapiroinitdaemon() 188764562Sgshapiro{ 188890792Sgshapiro if (NDaemons == 0) 188964562Sgshapiro { 189090792Sgshapiro Daemons[NDaemons].d_socket = -1; 189190792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 189290792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 189390792Sgshapiro NDaemons = 1; 189464562Sgshapiro } 189564562Sgshapiro} 189690792Sgshapiro/* 189764562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 189864562Sgshapiro** 189964562Sgshapiro** Parameters: 190064562Sgshapiro** p -- the options line. 190164562Sgshapiro** 190264562Sgshapiro** Returns: 190364562Sgshapiro** none. 190464562Sgshapiro*/ 190564562Sgshapiro 190690792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 190764562Sgshapiro 190864562Sgshapirovoid 190964562Sgshapirosetclientoptions(p) 191064562Sgshapiro register char *p; 191164562Sgshapiro{ 191290792Sgshapiro int family; 191390792Sgshapiro DAEMON_T d; 191464562Sgshapiro 191564562Sgshapiro memset(&d, '\0', sizeof d); 191664562Sgshapiro setsockaddroptions(p, &d); 191764562Sgshapiro 191864562Sgshapiro /* grab what we need */ 191990792Sgshapiro family = d.d_addr.sa.sa_family; 192090792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 192190792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 192290792Sgshapiro if (d.d_name != NULL) 192390792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 192464562Sgshapiro else 192590792Sgshapiro { 192690792Sgshapiro char num[30]; 192790792Sgshapiro 192890792Sgshapiro (void) sm_snprintf(num, sizeof num, "Client%d", family); 192990792Sgshapiro ClientSettings[family].d_name = newstr(num); 193090792Sgshapiro } 193164562Sgshapiro} 193290792Sgshapiro/* 193364562Sgshapiro** ADDR_FAMILY -- determine address family from address 193464562Sgshapiro** 193564562Sgshapiro** Parameters: 193664562Sgshapiro** addr -- the string representation of the address 193764562Sgshapiro** 193864562Sgshapiro** Returns: 193964562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 194064562Sgshapiro** 194164562Sgshapiro** Side Effects: 194264562Sgshapiro** none. 194364562Sgshapiro*/ 194464562Sgshapiro 194564562Sgshapirostatic int 194664562Sgshapiroaddr_family(addr) 194764562Sgshapiro char *addr; 194864562Sgshapiro{ 194990792Sgshapiro#if NETINET6 195064562Sgshapiro SOCKADDR clt_addr; 195190792Sgshapiro#endif /* NETINET6 */ 195264562Sgshapiro 195390792Sgshapiro#if NETINET 195464562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 195564562Sgshapiro { 195664562Sgshapiro if (tTd(16, 9)) 195790792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 195864562Sgshapiro return AF_INET; 195964562Sgshapiro } 196090792Sgshapiro#endif /* NETINET */ 196190792Sgshapiro#if NETINET6 196290792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 196364562Sgshapiro { 196464562Sgshapiro if (tTd(16, 9)) 196590792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 196664562Sgshapiro return AF_INET6; 196764562Sgshapiro } 196890792Sgshapiro#endif /* NETINET6 */ 196990792Sgshapiro#if _FFR_DAEMON_NETUNIX 197090792Sgshapiro# if NETUNIX 197190792Sgshapiro if (*addr == '/') 197290792Sgshapiro { 197390792Sgshapiro if (tTd(16, 9)) 197490792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 197590792Sgshapiro return AF_UNIX; 197690792Sgshapiro } 197790792Sgshapiro# endif /* NETUNIX */ 197890792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 197964562Sgshapiro if (tTd(16, 9)) 198090792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 198164562Sgshapiro return AF_UNSPEC; 198264562Sgshapiro} 198390792Sgshapiro 198490792Sgshapiro/* 198590792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 198690792Sgshapiro** 198790792Sgshapiro** Parameters: 198890792Sgshapiro** flag -- the flag to test. 198990792Sgshapiro** 199090792Sgshapiro** Returns: 199190792Sgshapiro** true iff all configured clients have set the flag. 199290792Sgshapiro*/ 199390792Sgshapiro 199490792Sgshapirobool 199590792Sgshapirochkclientmodifiers(flag) 199690792Sgshapiro int flag; 199790792Sgshapiro{ 199890792Sgshapiro int i; 199990792Sgshapiro bool flagisset; 200090792Sgshapiro 200190792Sgshapiro flagisset = false; 200290792Sgshapiro for (i = 0; i < AF_MAX; i++) 200390792Sgshapiro { 200490792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 200590792Sgshapiro { 200690792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 200790792Sgshapiro return false; 200890792Sgshapiro flagisset = true; 200990792Sgshapiro } 201090792Sgshapiro } 201190792Sgshapiro return flagisset; 201290792Sgshapiro} 201390792Sgshapiro 201490792Sgshapiro#if MILTER 201590792Sgshapiro/* 201690792Sgshapiro** SETUP_DAEMON_FILTERS -- Parse per-socket filters 201790792Sgshapiro** 201890792Sgshapiro** Parameters: 201990792Sgshapiro** none 202090792Sgshapiro** 202190792Sgshapiro** Returns: 202290792Sgshapiro** none 202390792Sgshapiro*/ 202490792Sgshapiro 202590792Sgshapirovoid 202690792Sgshapirosetup_daemon_milters() 202790792Sgshapiro{ 202890792Sgshapiro int idx; 202990792Sgshapiro 203090792Sgshapiro if (OpMode == MD_SMTP) 203190792Sgshapiro { 203290792Sgshapiro /* no need to configure the daemons */ 203390792Sgshapiro return; 203490792Sgshapiro } 203590792Sgshapiro 203690792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 203790792Sgshapiro { 203890792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 203990792Sgshapiro { 204090792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 204190792Sgshapiro Daemons[idx].d_inputfilters, 204290792Sgshapiro MAXFILTERS); 204390792Sgshapiro } 204490792Sgshapiro } 204590792Sgshapiro} 204690792Sgshapiro#endif /* MILTER */ 204790792Sgshapiro/* 204864562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 204964562Sgshapiro** 205064562Sgshapiro** Parameters: 205138032Speter** host -- the name of the host. 205238032Speter** port -- the port number to connect to. 205338032Speter** mci -- a pointer to the mail connection information 205438032Speter** structure to be filled in. 205538032Speter** e -- the current envelope. 205690792Sgshapiro** enough -- time at which to stop further connection attempts. 205790792Sgshapiro** (0 means no limit) 205838032Speter** 205938032Speter** Returns: 206038032Speter** An exit code telling whether the connection could be 206138032Speter** made and if not why not. 206238032Speter** 206338032Speter** Side Effects: 206438032Speter** none. 206538032Speter*/ 206638032Speter 206738032Speterstatic jmp_buf CtxConnectTimeout; 206838032Speter 206938032SpeterSOCKADDR CurHostAddr; /* address of current host */ 207038032Speter 207138032Speterint 207290792Sgshapiromakeconnection(host, port, mci, e, enough) 207338032Speter char *host; 207490792Sgshapiro volatile unsigned int port; 207538032Speter register MCI *mci; 207638032Speter ENVELOPE *e; 207790792Sgshapiro time_t enough; 207838032Speter{ 207938032Speter register volatile int addrno = 0; 208090792Sgshapiro volatile int s; 208190792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 208238032Speter SOCKADDR addr; 208364562Sgshapiro SOCKADDR clt_addr; 208464562Sgshapiro int save_errno = 0; 208564562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 208638032Speter volatile bool firstconnect; 208790792Sgshapiro SM_EVENT *volatile ev = NULL; 208890792Sgshapiro#if NETINET6 208990792Sgshapiro volatile bool v6found = false; 209090792Sgshapiro#endif /* NETINET6 */ 209164562Sgshapiro volatile int family = InetMode; 209264562Sgshapiro SOCKADDR_LEN_T len; 209364562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 209464562Sgshapiro volatile bool clt_bind; 209564562Sgshapiro BITMAP256 d_flags; 209664562Sgshapiro char *p; 209764562Sgshapiro extern ENVELOPE BlankEnvelope; 209838032Speter 209990792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 210064562Sgshapiro clrbitmap(d_flags); 210190792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 210264562Sgshapiro { 210364562Sgshapiro for (; *p != '\0'; p++) 210464562Sgshapiro { 210564562Sgshapiro if (!(isascii(*p) && isspace(*p))) 210671345Sgshapiro setbitn(bitidx(*p), d_flags); 210764562Sgshapiro } 210864562Sgshapiro } 210964562Sgshapiro 211090792Sgshapiro#if NETINET6 211164562Sgshapiro v4retry: 211290792Sgshapiro#endif /* NETINET6 */ 211390792Sgshapiro clt_bind = false; 211464562Sgshapiro 211564562Sgshapiro /* Set up the address for outgoing connection. */ 211664562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 211790792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 211873188Sgshapiro *p != '\0') 211964562Sgshapiro { 212090792Sgshapiro#if NETINET6 212164562Sgshapiro char p6[INET6_ADDRSTRLEN]; 212290792Sgshapiro#endif /* NETINET6 */ 212364562Sgshapiro 212464562Sgshapiro memset(&clt_addr, '\0', sizeof clt_addr); 212564562Sgshapiro 212664562Sgshapiro /* infer the address family from the address itself */ 212764562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 212864562Sgshapiro switch (clt_addr.sa.sa_family) 212964562Sgshapiro { 213090792Sgshapiro#if NETINET 213164562Sgshapiro case AF_INET: 213273188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 213373188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 213473188Sgshapiro clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK) 213564562Sgshapiro { 213690792Sgshapiro clt_bind = true; 213764562Sgshapiro socksize = sizeof (struct sockaddr_in); 213864562Sgshapiro } 213964562Sgshapiro break; 214090792Sgshapiro#endif /* NETINET */ 214164562Sgshapiro 214290792Sgshapiro#if NETINET6 214364562Sgshapiro case AF_INET6: 214464562Sgshapiro if (inet_addr(p) != INADDR_NONE) 214590792Sgshapiro (void) sm_snprintf(p6, sizeof p6, 214690792Sgshapiro "IPv6:::ffff:%s", p); 214764562Sgshapiro else 214890792Sgshapiro (void) sm_strlcpy(p6, p, sizeof p6); 214990792Sgshapiro if (anynet_pton(AF_INET6, p6, 215090792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 215173188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 215264562Sgshapiro { 215390792Sgshapiro clt_bind = true; 215464562Sgshapiro socksize = sizeof (struct sockaddr_in6); 215564562Sgshapiro } 215664562Sgshapiro break; 215790792Sgshapiro#endif /* NETINET6 */ 215864562Sgshapiro 215990792Sgshapiro#if 0 216064562Sgshapiro default: 216164562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 216264562Sgshapiro clt_addr.sa.sa_family); 216364562Sgshapiro break; 216490792Sgshapiro#endif /* 0 */ 216564562Sgshapiro } 216664562Sgshapiro if (clt_bind) 216764562Sgshapiro family = clt_addr.sa.sa_family; 216864562Sgshapiro } 216990792Sgshapiro 217090792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 217190792Sgshapiro if (!clt_bind) 217264562Sgshapiro { 217390792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 217464562Sgshapiro switch (clt_addr.sa.sa_family) 217564562Sgshapiro { 217690792Sgshapiro#if NETINET 217764562Sgshapiro case AF_INET: 217864562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 217964562Sgshapiro clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 218064562Sgshapiro else 218190792Sgshapiro clt_bind = true; 218264562Sgshapiro if (clt_addr.sin.sin_port != 0) 218390792Sgshapiro clt_bind = true; 218464562Sgshapiro socksize = sizeof (struct sockaddr_in); 218564562Sgshapiro break; 218690792Sgshapiro#endif /* NETINET */ 218790792Sgshapiro#if NETINET6 218864562Sgshapiro case AF_INET6: 218964562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 219064562Sgshapiro clt_addr.sin6.sin6_addr = in6addr_any; 219164562Sgshapiro else 219290792Sgshapiro clt_bind = true; 219364562Sgshapiro socksize = sizeof (struct sockaddr_in6); 219464562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 219590792Sgshapiro clt_bind = true; 219664562Sgshapiro break; 219790792Sgshapiro#endif /* NETINET6 */ 219890792Sgshapiro#if NETISO 219964562Sgshapiro case AF_ISO: 220064562Sgshapiro socksize = sizeof clt_addr.siso; 220190792Sgshapiro clt_bind = true; 220264562Sgshapiro break; 220390792Sgshapiro#endif /* NETISO */ 220464562Sgshapiro default: 220564562Sgshapiro break; 220664562Sgshapiro } 220764562Sgshapiro } 220864562Sgshapiro 220938032Speter /* 221038032Speter ** Set up the address for the mailer. 221138032Speter ** Accept "[a.b.c.d]" syntax for host name. 221238032Speter */ 221338032Speter 221473188Sgshapiro SM_SET_H_ERRNO(0); 221538032Speter errno = 0; 221664562Sgshapiro memset(&CurHostAddr, '\0', sizeof CurHostAddr); 221764562Sgshapiro memset(&addr, '\0', sizeof addr); 221838032Speter SmtpPhase = mci->mci_phase = "initial connection"; 221938032Speter CurHostName = host; 222038032Speter 222138032Speter if (host[0] == '[') 222238032Speter { 222364562Sgshapiro p = strchr(host, ']'); 222438032Speter if (p != NULL) 222538032Speter { 222690792Sgshapiro#if NETINET 222764562Sgshapiro unsigned long hid = INADDR_NONE; 222890792Sgshapiro#endif /* NETINET */ 222990792Sgshapiro#if NETINET6 223064562Sgshapiro struct sockaddr_in6 hid6; 223190792Sgshapiro#endif /* NETINET6 */ 223264562Sgshapiro 223338032Speter *p = '\0'; 223490792Sgshapiro#if NETINET6 223564562Sgshapiro memset(&hid6, '\0', sizeof hid6); 223690792Sgshapiro#endif /* NETINET6 */ 223790792Sgshapiro#if NETINET 223864562Sgshapiro if (family == AF_INET && 223964562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 224038032Speter { 224164562Sgshapiro addr.sin.sin_family = AF_INET; 224264562Sgshapiro addr.sin.sin_addr.s_addr = hid; 224364562Sgshapiro } 224464562Sgshapiro else 224590792Sgshapiro#endif /* NETINET */ 224690792Sgshapiro#if NETINET6 224764562Sgshapiro if (family == AF_INET6 && 224890792Sgshapiro anynet_pton(AF_INET6, &host[1], 224990792Sgshapiro &hid6.sin6_addr) == 1) 225064562Sgshapiro { 225164562Sgshapiro addr.sin6.sin6_family = AF_INET6; 225264562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 225364562Sgshapiro } 225464562Sgshapiro else 225590792Sgshapiro#endif /* NETINET6 */ 225664562Sgshapiro { 225738032Speter /* try it as a host name (avoid MX lookup) */ 225864562Sgshapiro hp = sm_gethostbyname(&host[1], family); 225938032Speter if (hp == NULL && p[-1] == '.') 226038032Speter { 226190792Sgshapiro#if NAMED_BIND 226238032Speter int oldopts = _res.options; 226338032Speter 226438032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 226590792Sgshapiro#endif /* NAMED_BIND */ 226638032Speter p[-1] = '\0'; 226764562Sgshapiro hp = sm_gethostbyname(&host[1], 226864562Sgshapiro family); 226938032Speter p[-1] = '.'; 227090792Sgshapiro#if NAMED_BIND 227138032Speter _res.options = oldopts; 227290792Sgshapiro#endif /* NAMED_BIND */ 227338032Speter } 227438032Speter *p = ']'; 227538032Speter goto gothostent; 227638032Speter } 227738032Speter *p = ']'; 227838032Speter } 227938032Speter if (p == NULL) 228038032Speter { 228138032Speter extern char MsgBuf[]; 228238032Speter 228364562Sgshapiro usrerrenh("5.1.2", 228464562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 228564562Sgshapiro host); 228638032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 228764562Sgshapiro errno = EINVAL; 228838032Speter return EX_NOHOST; 228938032Speter } 229038032Speter } 229138032Speter else 229238032Speter { 229338032Speter /* contortion to get around SGI cc complaints */ 229438032Speter { 229564562Sgshapiro p = &host[strlen(host) - 1]; 229664562Sgshapiro hp = sm_gethostbyname(host, family); 229738032Speter if (hp == NULL && *p == '.') 229838032Speter { 229990792Sgshapiro#if NAMED_BIND 230038032Speter int oldopts = _res.options; 230138032Speter 230238032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 230390792Sgshapiro#endif /* NAMED_BIND */ 230438032Speter *p = '\0'; 230564562Sgshapiro hp = sm_gethostbyname(host, family); 230638032Speter *p = '.'; 230790792Sgshapiro#if NAMED_BIND 230838032Speter _res.options = oldopts; 230990792Sgshapiro#endif /* NAMED_BIND */ 231038032Speter } 231138032Speter } 231238032Spetergothostent: 231338032Speter if (hp == NULL) 231438032Speter { 231590792Sgshapiro#if NAMED_BIND 231638032Speter /* check for name server timeouts */ 231790792Sgshapiro# if NETINET6 231890792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 231990792Sgshapiro errno == ETIMEDOUT) 232038032Speter { 232190792Sgshapiro /* 232290792Sgshapiro ** An attempt with family AF_INET may 232390792Sgshapiro ** succeed By skipping the next section 232490792Sgshapiro ** of code, we will try AF_INET before 232590792Sgshapiro ** failing. 232690792Sgshapiro */ 232790792Sgshapiro 232890792Sgshapiro if (tTd(16, 10)) 232990792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 233038032Speter } 233190792Sgshapiro else 233290792Sgshapiro# endif /* NETINET6 */ 233390792Sgshapiro { 233490792Sgshapiro if (errno == ETIMEDOUT || 233590792Sgshapiro h_errno == TRY_AGAIN || 233690792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 233790792Sgshapiro { 233890792Sgshapiro save_errno = errno; 233990792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 234090792Sgshapiro "4.4.3", NULL); 234190792Sgshapiro errno = save_errno; 234290792Sgshapiro return EX_TEMPFAIL; 234390792Sgshapiro } 234490792Sgshapiro } 234590792Sgshapiro#endif /* NAMED_BIND */ 234690792Sgshapiro#if NETINET6 234764562Sgshapiro /* 234864562Sgshapiro ** Try v6 first, then fall back to v4. 234964562Sgshapiro ** If we found a v6 address, but no v4 235064562Sgshapiro ** addresses, then TEMPFAIL. 235164562Sgshapiro */ 235264562Sgshapiro 235364562Sgshapiro if (family == AF_INET6) 235464562Sgshapiro { 235564562Sgshapiro family = AF_INET; 235664562Sgshapiro goto v4retry; 235764562Sgshapiro } 235864562Sgshapiro if (v6found) 235964562Sgshapiro goto v6tempfail; 236090792Sgshapiro#endif /* NETINET6 */ 236164562Sgshapiro save_errno = errno; 236238032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 236364562Sgshapiro errno = save_errno; 236464562Sgshapiro return EX_NOHOST; 236538032Speter } 236638032Speter addr.sa.sa_family = hp->h_addrtype; 236738032Speter switch (hp->h_addrtype) 236838032Speter { 236990792Sgshapiro#if NETINET 237038032Speter case AF_INET: 237164562Sgshapiro memmove(&addr.sin.sin_addr, 237264562Sgshapiro hp->h_addr, 237338032Speter INADDRSZ); 237438032Speter break; 237590792Sgshapiro#endif /* NETINET */ 237638032Speter 237790792Sgshapiro#if NETINET6 237864562Sgshapiro case AF_INET6: 237964562Sgshapiro memmove(&addr.sin6.sin6_addr, 238064562Sgshapiro hp->h_addr, 238164562Sgshapiro IN6ADDRSZ); 238264562Sgshapiro break; 238390792Sgshapiro#endif /* NETINET6 */ 238464562Sgshapiro 238538032Speter default: 238638032Speter if (hp->h_length > sizeof addr.sa.sa_data) 238738032Speter { 238838032Speter syserr("makeconnection: long sa_data: family %d len %d", 238938032Speter hp->h_addrtype, hp->h_length); 239038032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 239164562Sgshapiro errno = EINVAL; 239238032Speter return EX_NOHOST; 239338032Speter } 239490792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 239538032Speter break; 239638032Speter } 239738032Speter addrno = 1; 239838032Speter } 239938032Speter 240038032Speter /* 240138032Speter ** Determine the port number. 240238032Speter */ 240338032Speter 240438032Speter if (port == 0) 240538032Speter { 240690792Sgshapiro#ifdef NO_GETSERVBYNAME 240764562Sgshapiro port = htons(25); 240890792Sgshapiro#else /* NO_GETSERVBYNAME */ 240938032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 241038032Speter 241138032Speter if (sp == NULL) 241238032Speter { 241338032Speter if (LogLevel > 2) 241438032Speter sm_syslog(LOG_ERR, NOQID, 241564562Sgshapiro "makeconnection: service \"smtp\" unknown"); 241638032Speter port = htons(25); 241738032Speter } 241838032Speter else 241938032Speter port = sp->s_port; 242090792Sgshapiro#endif /* NO_GETSERVBYNAME */ 242138032Speter } 242238032Speter 242390792Sgshapiro#if NETINET6 242490792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 242590792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 242690792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 242790792Sgshapiro { 242890792Sgshapiro /* 242990792Sgshapiro ** Ignore mapped IPv4 address since 243090792Sgshapiro ** there is a ClientPortOptions setting 243190792Sgshapiro ** for IPv4. 243290792Sgshapiro */ 243390792Sgshapiro 243490792Sgshapiro goto nextaddr; 243590792Sgshapiro } 243690792Sgshapiro#endif /* NETINET6 */ 243790792Sgshapiro 243838032Speter switch (addr.sa.sa_family) 243938032Speter { 244090792Sgshapiro#if NETINET 244138032Speter case AF_INET: 244238032Speter addr.sin.sin_port = port; 244338032Speter addrlen = sizeof (struct sockaddr_in); 244438032Speter break; 244590792Sgshapiro#endif /* NETINET */ 244638032Speter 244790792Sgshapiro#if NETINET6 244864562Sgshapiro case AF_INET6: 244964562Sgshapiro addr.sin6.sin6_port = port; 245064562Sgshapiro addrlen = sizeof (struct sockaddr_in6); 245164562Sgshapiro break; 245290792Sgshapiro#endif /* NETINET6 */ 245364562Sgshapiro 245490792Sgshapiro#if NETISO 245538032Speter case AF_ISO: 245638032Speter /* assume two byte transport selector */ 245764562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 245838032Speter addrlen = sizeof (struct sockaddr_iso); 245938032Speter break; 246090792Sgshapiro#endif /* NETISO */ 246138032Speter 246238032Speter default: 246338032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 246438032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 246564562Sgshapiro errno = EINVAL; 246690792Sgshapiro#if NETINET6 246771345Sgshapiro if (hp != NULL) 246871345Sgshapiro freehostent(hp); 246990792Sgshapiro#endif /* NETINET6 */ 247064562Sgshapiro return EX_NOHOST; 247138032Speter } 247238032Speter 247338032Speter /* 247438032Speter ** Try to actually open the connection. 247538032Speter */ 247638032Speter 247790792Sgshapiro#if XLA 247838032Speter /* if too many connections, don't bother trying */ 247938032Speter if (!xla_noqueue_ok(host)) 248071345Sgshapiro { 248190792Sgshapiro# if NETINET6 248271345Sgshapiro if (hp != NULL) 248371345Sgshapiro freehostent(hp); 248490792Sgshapiro# endif /* NETINET6 */ 248538032Speter return EX_TEMPFAIL; 248671345Sgshapiro } 248790792Sgshapiro#endif /* XLA */ 248838032Speter 248990792Sgshapiro firstconnect = true; 249038032Speter for (;;) 249138032Speter { 249238032Speter if (tTd(16, 1)) 249390792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 249490792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 249590792Sgshapiro (int) addr.sa.sa_family); 249638032Speter 249738032Speter /* save for logging */ 249838032Speter CurHostAddr = addr; 249938032Speter 250090792Sgshapiro#if HASRRESVPORT 250138032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 250238032Speter { 250338032Speter int rport = IPPORT_RESERVED - 1; 250438032Speter 250538032Speter s = rresvport(&rport); 250638032Speter } 250738032Speter else 250890792Sgshapiro#endif /* HASRRESVPORT */ 250938032Speter { 251090792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 251138032Speter } 251238032Speter if (s < 0) 251338032Speter { 251464562Sgshapiro save_errno = errno; 251538032Speter syserr("makeconnection: cannot create socket"); 251690792Sgshapiro#if XLA 251738032Speter xla_host_end(host); 251890792Sgshapiro#endif /* XLA */ 251938032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 252090792Sgshapiro#if NETINET6 252171345Sgshapiro if (hp != NULL) 252271345Sgshapiro freehostent(hp); 252390792Sgshapiro#endif /* NETINET6 */ 252464562Sgshapiro errno = save_errno; 252538032Speter return EX_TEMPFAIL; 252638032Speter } 252738032Speter 252890792Sgshapiro#ifdef SO_SNDBUF 252990792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 253038032Speter { 253138032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 253290792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 253390792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 253438032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 253538032Speter } 253690792Sgshapiro#endif /* SO_SNDBUF */ 253790792Sgshapiro#ifdef SO_RCVBUF 253890792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 253964562Sgshapiro { 254064562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 254190792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 254290792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 254364562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 254464562Sgshapiro } 254590792Sgshapiro#endif /* SO_RCVBUF */ 254638032Speter 254738032Speter if (tTd(16, 1)) 254890792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 254938032Speter 255038032Speter /* turn on network debugging? */ 255138032Speter if (tTd(16, 101)) 255238032Speter { 255338032Speter int on = 1; 255464562Sgshapiro 255538032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 255638032Speter (char *)&on, sizeof on); 255738032Speter } 255890792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 255990792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 256090792Sgshapiro errno = 0; /* for debugging */ 256138032Speter 256264562Sgshapiro if (clt_bind) 256364562Sgshapiro { 256464562Sgshapiro int on = 1; 256564562Sgshapiro 256664562Sgshapiro switch (clt_addr.sa.sa_family) 256764562Sgshapiro { 256890792Sgshapiro#if NETINET 256964562Sgshapiro case AF_INET: 257064562Sgshapiro if (clt_addr.sin.sin_port != 0) 257164562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 257264562Sgshapiro SO_REUSEADDR, 257364562Sgshapiro (char *) &on, 257464562Sgshapiro sizeof on); 257564562Sgshapiro break; 257690792Sgshapiro#endif /* NETINET */ 257764562Sgshapiro 257890792Sgshapiro#if NETINET6 257964562Sgshapiro case AF_INET6: 258064562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 258164562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 258264562Sgshapiro SO_REUSEADDR, 258364562Sgshapiro (char *) &on, 258464562Sgshapiro sizeof on); 258564562Sgshapiro break; 258690792Sgshapiro#endif /* NETINET6 */ 258764562Sgshapiro } 258864562Sgshapiro 258964562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 259064562Sgshapiro { 259164562Sgshapiro save_errno = errno; 259264562Sgshapiro (void) close(s); 259364562Sgshapiro errno = save_errno; 259464562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 259564562Sgshapiro anynet_ntoa(&clt_addr)); 259690792Sgshapiro#if NETINET6 259771345Sgshapiro if (hp != NULL) 259871345Sgshapiro freehostent(hp); 259990792Sgshapiro#endif /* NETINET6 */ 260064562Sgshapiro errno = save_errno; 260164562Sgshapiro return EX_TEMPFAIL; 260264562Sgshapiro } 260364562Sgshapiro } 260464562Sgshapiro 260538032Speter /* 260638032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 260738032Speter ** Time out the connect to avoid this problem. 260838032Speter */ 260938032Speter 261038032Speter if (setjmp(CtxConnectTimeout) == 0) 261138032Speter { 261238032Speter int i; 261338032Speter 261438032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 261590792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 261690792Sgshapiro connecttimeout, 0); 261738032Speter else if (TimeOuts.to_connect != 0) 261890792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 261990792Sgshapiro connecttimeout, 0); 262038032Speter else 262138032Speter ev = NULL; 262238032Speter 262364562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 262464562Sgshapiro { 262590792Sgshapiro#if NETINET 262664562Sgshapiro case AF_INET: 262764562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 262864562Sgshapiro break; 262990792Sgshapiro#endif /* NETINET */ 263064562Sgshapiro 263190792Sgshapiro#if NETINET6 263264562Sgshapiro case AF_INET6: 263364562Sgshapiro memmove(&addr.sin6.sin6_addr, 263464562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 263564562Sgshapiro IN6ADDRSZ); 263664562Sgshapiro break; 263790792Sgshapiro#endif /* NETINET6 */ 263864562Sgshapiro } 2639141858Sgshapiro if (tTd(16, 1)) 2640141858Sgshapiro sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr)); 264138032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 264264562Sgshapiro save_errno = errno; 264338032Speter if (ev != NULL) 264490792Sgshapiro sm_clrevent(ev); 264538032Speter if (i >= 0) 264638032Speter break; 264738032Speter } 264838032Speter else 264964562Sgshapiro save_errno = errno; 265038032Speter 265194334Sgshapiro /* couldn't connect.... figure out why */ 265294334Sgshapiro (void) close(s); 265394334Sgshapiro 265438032Speter /* if running demand-dialed connection, try again */ 265590792Sgshapiro if (DialDelay > 0 && firstconnect && 265690792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 265738032Speter { 265838032Speter if (tTd(16, 1)) 265990792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 266090792Sgshapiro sm_errstring(save_errno)); 266190792Sgshapiro firstconnect = false; 266264562Sgshapiro (void) sleep(DialDelay); 266338032Speter continue; 266438032Speter } 266538032Speter 266690792Sgshapiro if (LogLevel > 13) 266738032Speter sm_syslog(LOG_INFO, e->e_id, 266838032Speter "makeconnection (%s [%s]) failed: %s", 266938032Speter host, anynet_ntoa(&addr), 267090792Sgshapiro sm_errstring(save_errno)); 267138032Speter 267290792Sgshapiro#if NETINET6 267390792Sgshapironextaddr: 267490792Sgshapiro#endif /* NETINET6 */ 267590792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 267690792Sgshapiro (enough == 0 || curtime() < enough)) 267738032Speter { 267838032Speter if (tTd(16, 1)) 267990792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 268090792Sgshapiro sm_errstring(save_errno)); 268138032Speter switch (addr.sa.sa_family) 268238032Speter { 268390792Sgshapiro#if NETINET 268438032Speter case AF_INET: 268564562Sgshapiro memmove(&addr.sin.sin_addr, 268664562Sgshapiro hp->h_addr_list[addrno++], 268764562Sgshapiro INADDRSZ); 268838032Speter break; 268990792Sgshapiro#endif /* NETINET */ 269038032Speter 269190792Sgshapiro#if NETINET6 269264562Sgshapiro case AF_INET6: 269364562Sgshapiro memmove(&addr.sin6.sin6_addr, 269464562Sgshapiro hp->h_addr_list[addrno++], 269564562Sgshapiro IN6ADDRSZ); 269664562Sgshapiro break; 269790792Sgshapiro#endif /* NETINET6 */ 269864562Sgshapiro 269938032Speter default: 270064562Sgshapiro memmove(addr.sa.sa_data, 270164562Sgshapiro hp->h_addr_list[addrno++], 270238032Speter hp->h_length); 270338032Speter break; 270438032Speter } 270538032Speter continue; 270638032Speter } 270764562Sgshapiro errno = save_errno; 270838032Speter 270990792Sgshapiro#if NETINET6 271064562Sgshapiro if (family == AF_INET6) 271164562Sgshapiro { 271264562Sgshapiro if (tTd(16, 1)) 271390792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 271490792Sgshapiro sm_errstring(save_errno)); 271590792Sgshapiro v6found = true; 271664562Sgshapiro family = AF_INET; 271771345Sgshapiro if (hp != NULL) 271871345Sgshapiro { 271971345Sgshapiro freehostent(hp); 272071345Sgshapiro hp = NULL; 272171345Sgshapiro } 272264562Sgshapiro goto v4retry; 272364562Sgshapiro } 272464562Sgshapiro v6tempfail: 272590792Sgshapiro#endif /* NETINET6 */ 272638032Speter /* couldn't open connection */ 272790792Sgshapiro#if NETINET6 272864562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 272964562Sgshapiro if (errno > 0) 273090792Sgshapiro#endif /* NETINET6 */ 273164562Sgshapiro save_errno = errno; 273264562Sgshapiro if (tTd(16, 1)) 273390792Sgshapiro sm_dprintf("Connect failed (%s)\n", 273490792Sgshapiro sm_errstring(save_errno)); 273590792Sgshapiro#if XLA 273638032Speter xla_host_end(host); 273790792Sgshapiro#endif /* XLA */ 273838032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 273990792Sgshapiro#if NETINET6 274071345Sgshapiro if (hp != NULL) 274171345Sgshapiro freehostent(hp); 274290792Sgshapiro#endif /* NETINET6 */ 274364562Sgshapiro errno = save_errno; 274438032Speter return EX_TEMPFAIL; 274538032Speter } 274638032Speter 274790792Sgshapiro#if NETINET6 274871345Sgshapiro if (hp != NULL) 274971345Sgshapiro { 275071345Sgshapiro freehostent(hp); 275171345Sgshapiro hp = NULL; 275271345Sgshapiro } 275390792Sgshapiro#endif /* NETINET6 */ 275471345Sgshapiro 275538032Speter /* connection ok, put it into canonical form */ 275664562Sgshapiro mci->mci_out = NULL; 275790792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 275890792Sgshapiro (void *) &s, 2759132943Sgshapiro SM_IO_WRONLY_B, NULL)) == NULL || 276038032Speter (s = dup(s)) < 0 || 276190792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 276290792Sgshapiro (void *) &s, 2763132943Sgshapiro SM_IO_RDONLY_B, NULL)) == NULL) 276438032Speter { 276564562Sgshapiro save_errno = errno; 276638032Speter syserr("cannot open SMTP client channel, fd=%d", s); 276738032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 276864562Sgshapiro if (mci->mci_out != NULL) 276990792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 277064562Sgshapiro (void) close(s); 277164562Sgshapiro errno = save_errno; 277238032Speter return EX_TEMPFAIL; 277338032Speter } 277490792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 277538032Speter 277690792Sgshapiro /* set {client_flags} */ 277790792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 277890792Sgshapiro { 277990792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 278090792Sgshapiro macid("{client_flags}"), 278190792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 278290792Sgshapiro } 278390792Sgshapiro else 278490792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 278590792Sgshapiro macid("{client_flags}"), ""); 278690792Sgshapiro 278790792Sgshapiro /* "add" {client_flags} to bitmap */ 278890792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 278990792Sgshapiro { 279090792Sgshapiro /* look for just this one flag */ 279190792Sgshapiro setbitn(D_IFNHELO, d_flags); 279290792Sgshapiro } 279390792Sgshapiro 279464562Sgshapiro /* find out name for Interface through which we connect */ 279564562Sgshapiro len = sizeof addr; 279664562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 279764562Sgshapiro { 279864562Sgshapiro char *name; 279990792Sgshapiro char family[5]; 280064562Sgshapiro 280190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 280290792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 280390792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 280490792Sgshapiro addr.sa.sa_family); 280590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 280690792Sgshapiro macid("{if_family_out}"), family); 280764562Sgshapiro 280864562Sgshapiro name = hostnamebyanyaddr(&addr); 280990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 281090792Sgshapiro macid("{if_name_out}"), name); 281164562Sgshapiro if (LogLevel > 11) 281264562Sgshapiro { 281364562Sgshapiro /* log connection information */ 281464562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 281564562Sgshapiro "SMTP outgoing connect on %.40s", name); 281664562Sgshapiro } 281764562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 281864562Sgshapiro { 281964562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 282064562Sgshapiro mci->mci_heloname = newstr(name); 282164562Sgshapiro } 282264562Sgshapiro } 282364562Sgshapiro else 282464562Sgshapiro { 282590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 282690792Sgshapiro macid("{if_name_out}"), NULL); 282790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 282890792Sgshapiro macid("{if_addr_out}"), NULL); 282990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 283090792Sgshapiro macid("{if_family_out}"), NULL); 283164562Sgshapiro } 2832132943Sgshapiro 2833132943Sgshapiro#if _FFR_HELONAME 2834132943Sgshapiro /* Use the configured HeloName as appropriate */ 2835132943Sgshapiro if (HeloName != NULL && HeloName[0] != '\0') 2836132943Sgshapiro mci->mci_heloname = newstr(HeloName); 2837132943Sgshapiro#endif /* _FFR_HELONAME */ 2838132943Sgshapiro 283938032Speter mci_setstat(mci, EX_OK, NULL, NULL); 284064562Sgshapiro return EX_OK; 284138032Speter} 284264562Sgshapiro 284364562Sgshapirostatic void 2844141858Sgshapiroconnecttimeout(ignore) 2845141858Sgshapiro int ignore; 284664562Sgshapiro{ 284777349Sgshapiro /* 284877349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 284977349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 285077349Sgshapiro ** DOING. 285177349Sgshapiro */ 285277349Sgshapiro 285364562Sgshapiro errno = ETIMEDOUT; 285464562Sgshapiro longjmp(CtxConnectTimeout, 1); 285564562Sgshapiro} 285690792Sgshapiro/* 285764562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 285864562Sgshapiro** 285964562Sgshapiro** Parameters: 286064562Sgshapiro** mux_path -- the path of the socket to connect to. 286164562Sgshapiro** mci -- a pointer to the mail connection information 286264562Sgshapiro** structure to be filled in. 286364562Sgshapiro** 286464562Sgshapiro** Returns: 286564562Sgshapiro** An exit code telling whether the connection could be 286664562Sgshapiro** made and if not why not. 286764562Sgshapiro** 286864562Sgshapiro** Side Effects: 286964562Sgshapiro** none. 287064562Sgshapiro*/ 287164562Sgshapiro 287290792Sgshapiro#if NETUNIX 287390792Sgshapiroint 287490792Sgshapiromakeconnection_ds(mux_path, mci) 287564562Sgshapiro char *mux_path; 287664562Sgshapiro register MCI *mci; 287764562Sgshapiro{ 287864562Sgshapiro int sock; 287964562Sgshapiro int rval, save_errno; 288064562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 288164562Sgshapiro struct sockaddr_un unix_addr; 288264562Sgshapiro 288364562Sgshapiro /* if not safe, don't connect */ 288464562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 288564562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 288664562Sgshapiro 288764562Sgshapiro if (rval != 0) 288864562Sgshapiro { 2889132943Sgshapiro syserr("makeconnection_ds: unsafe domain socket %s", 2890132943Sgshapiro mux_path); 289164562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 289264562Sgshapiro errno = rval; 289364562Sgshapiro return EX_TEMPFAIL; 289464562Sgshapiro } 289564562Sgshapiro 289664562Sgshapiro /* prepare address structure */ 289764562Sgshapiro memset(&unix_addr, '\0', sizeof unix_addr); 289864562Sgshapiro unix_addr.sun_family = AF_UNIX; 289964562Sgshapiro 290064562Sgshapiro if (strlen(mux_path) >= sizeof unix_addr.sun_path) 290164562Sgshapiro { 2902132943Sgshapiro syserr("makeconnection_ds: domain socket name %s too long", 2903132943Sgshapiro mux_path); 290490792Sgshapiro 290590792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 290664562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 290764562Sgshapiro errno = ENAMETOOLONG; 290864562Sgshapiro return EX_UNAVAILABLE; 290964562Sgshapiro } 291090792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 291190792Sgshapiro sizeof unix_addr.sun_path); 291264562Sgshapiro 291364562Sgshapiro /* initialize domain socket */ 291464562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 291564562Sgshapiro if (sock == -1) 291664562Sgshapiro { 291764562Sgshapiro save_errno = errno; 2918132943Sgshapiro syserr("makeconnection_ds: could not create domain socket %s", 2919132943Sgshapiro mux_path); 292064562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 292164562Sgshapiro errno = save_errno; 292264562Sgshapiro return EX_TEMPFAIL; 292364562Sgshapiro } 292464562Sgshapiro 292564562Sgshapiro /* connect to server */ 292664562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 292764562Sgshapiro sizeof(unix_addr)) == -1) 292864562Sgshapiro { 292964562Sgshapiro save_errno = errno; 293064562Sgshapiro syserr("Could not connect to socket %s", mux_path); 293164562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 293264562Sgshapiro (void) close(sock); 293364562Sgshapiro errno = save_errno; 293464562Sgshapiro return EX_TEMPFAIL; 293564562Sgshapiro } 293664562Sgshapiro 293764562Sgshapiro /* connection ok, put it into canonical form */ 293864562Sgshapiro mci->mci_out = NULL; 293990792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2940132943Sgshapiro (void *) &sock, SM_IO_WRONLY_B, NULL)) 294190792Sgshapiro == NULL 294290792Sgshapiro || (sock = dup(sock)) < 0 || 294390792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2944132943Sgshapiro (void *) &sock, SM_IO_RDONLY_B, NULL)) 294590792Sgshapiro == NULL) 294664562Sgshapiro { 294764562Sgshapiro save_errno = errno; 294864562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 294964562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 295064562Sgshapiro if (mci->mci_out != NULL) 295190792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 295264562Sgshapiro (void) close(sock); 295364562Sgshapiro errno = save_errno; 295464562Sgshapiro return EX_TEMPFAIL; 295564562Sgshapiro } 295690792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 295764562Sgshapiro 295864562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 295964562Sgshapiro errno = 0; 296064562Sgshapiro return EX_OK; 296164562Sgshapiro} 296290792Sgshapiro#endif /* NETUNIX */ 296390792Sgshapiro/* 296490792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 296577349Sgshapiro** 296677349Sgshapiro** Parameters: 296790792Sgshapiro** none. 296877349Sgshapiro** 296977349Sgshapiro** Returns: 297077349Sgshapiro** none. 297177349Sgshapiro** 297277349Sgshapiro** Side Effects: 297390792Sgshapiro** closes control socket, exits. 297477349Sgshapiro*/ 297577349Sgshapiro 297690792Sgshapirovoid 297790792Sgshapiroshutdown_daemon() 297877349Sgshapiro{ 297990792Sgshapiro int i; 298090792Sgshapiro char *reason; 298177349Sgshapiro 298290792Sgshapiro sm_allsignals(true); 298390792Sgshapiro 298490792Sgshapiro reason = ShutdownRequest; 298590792Sgshapiro ShutdownRequest = NULL; 298690792Sgshapiro PendingSignal = 0; 298790792Sgshapiro 2988132943Sgshapiro if (LogLevel > 9) 2989132943Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s", 299090792Sgshapiro reason == NULL ? "implicit call" : reason); 299190792Sgshapiro 299290792Sgshapiro FileName = NULL; 299390792Sgshapiro closecontrolsocket(true); 299490792Sgshapiro#if XLA 299590792Sgshapiro xla_all_end(); 299690792Sgshapiro#endif /* XLA */ 299790792Sgshapiro 299890792Sgshapiro for (i = 0; i < NDaemons; i++) 299990792Sgshapiro { 300090792Sgshapiro if (Daemons[i].d_socket >= 0) 300190792Sgshapiro { 300290792Sgshapiro (void) close(Daemons[i].d_socket); 300390792Sgshapiro Daemons[i].d_socket = -1; 300490792Sgshapiro 300590792Sgshapiro#if _FFR_DAEMON_NETUNIX 300690792Sgshapiro# if NETUNIX 300790792Sgshapiro /* Remove named sockets */ 300890792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 300990792Sgshapiro { 301090792Sgshapiro int rval; 301190792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 301290792Sgshapiro 301390792Sgshapiro /* if not safe, don't use it */ 301490792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 301590792Sgshapiro RunAsUid, RunAsGid, 301690792Sgshapiro RunAsUserName, sff, 301790792Sgshapiro S_IRUSR|S_IWUSR, NULL); 301890792Sgshapiro if (rval == 0 && 301990792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 302090792Sgshapiro { 302190792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 302290792Sgshapiro "Could not remove daemon %s socket: %s: %s", 302390792Sgshapiro Daemons[i].d_name, 302490792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 302590792Sgshapiro sm_errstring(errno)); 302690792Sgshapiro } 302790792Sgshapiro } 302890792Sgshapiro# endif /* NETUNIX */ 302990792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 303090792Sgshapiro } 303190792Sgshapiro } 303290792Sgshapiro 303390792Sgshapiro finis(false, true, EX_OK); 303477349Sgshapiro} 303590792Sgshapiro/* 303677349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 303777349Sgshapiro** 303877349Sgshapiro** Parameters: 303977349Sgshapiro** none. 304077349Sgshapiro** 304177349Sgshapiro** Returns: 304277349Sgshapiro** none. 304377349Sgshapiro** 304477349Sgshapiro** Side Effects: 304577349Sgshapiro** restarts the daemon or exits if restart fails. 304677349Sgshapiro*/ 304777349Sgshapiro 304880785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 304980785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 305080785Sgshapirodo \ 305180785Sgshapiro{ \ 305290792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 305380785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 305490792Sgshapiro (void) sm_signal((sig), (old)); \ 305580785Sgshapiro} while (0) 305680785Sgshapiro 305790792Sgshapirovoid 305877349Sgshapirorestart_daemon() 305977349Sgshapiro{ 306090792Sgshapiro bool drop; 306177349Sgshapiro int save_errno; 306277349Sgshapiro char *reason; 306380785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 306477349Sgshapiro extern int DtableSize; 306577349Sgshapiro 306680785Sgshapiro /* clear the events to turn off SIGALRMs */ 306790792Sgshapiro sm_clear_events(); 306890792Sgshapiro sm_allsignals(true); 306977349Sgshapiro 307077349Sgshapiro reason = RestartRequest; 307177349Sgshapiro RestartRequest = NULL; 307277349Sgshapiro PendingSignal = 0; 307377349Sgshapiro 307477349Sgshapiro if (SaveArgv[0][0] != '/') 307577349Sgshapiro { 307677349Sgshapiro if (LogLevel > 3) 307777349Sgshapiro sm_syslog(LOG_INFO, NOQID, 307877349Sgshapiro "could not restart: need full path"); 307990792Sgshapiro finis(false, true, EX_OSFILE); 308090792Sgshapiro /* NOTREACHED */ 308177349Sgshapiro } 308277349Sgshapiro if (LogLevel > 3) 308377349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 308477349Sgshapiro SaveArgv[0], 308577349Sgshapiro reason == NULL ? "implicit call" : reason); 308677349Sgshapiro 308790792Sgshapiro closecontrolsocket(true); 308898121Sgshapiro#if SM_CONF_SHM 308998121Sgshapiro cleanup_shm(DaemonPid == getpid()); 309098121Sgshapiro#endif /* SM_CONF_SHM */ 309190792Sgshapiro 3092132943Sgshapiro /* close locked pid file */ 3093132943Sgshapiro close_sendmail_pid(); 3094132943Sgshapiro 309590792Sgshapiro /* 309690792Sgshapiro ** Want to drop to the user who started the process in all cases 309790792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 309890792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 309990792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 310090792Sgshapiro */ 310190792Sgshapiro 310290792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 310390792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 310490792Sgshapiro 310590792Sgshapiro if (drop_privileges(drop) != EX_OK) 310677349Sgshapiro { 310777349Sgshapiro if (LogLevel > 0) 310877349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 310990792Sgshapiro "could not drop privileges: %s", 311090792Sgshapiro sm_errstring(errno)); 311190792Sgshapiro finis(false, true, EX_OSERR); 311290792Sgshapiro /* NOTREACHED */ 311377349Sgshapiro } 311477349Sgshapiro 3115132943Sgshapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 311677349Sgshapiro 311780785Sgshapiro /* 311880785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 311980785Sgshapiro ** However, the default action can be "terminate", so it isn't 312080785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 312180785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 312280785Sgshapiro */ 312380785Sgshapiro 312480785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 312580785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 312680785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 312780785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 312880785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 312980785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 313080785Sgshapiro#ifdef SIGUSR1 313180785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 313280785Sgshapiro#endif /* SIGUSR1 */ 313394334Sgshapiro 313494334Sgshapiro /* Turn back on signals */ 313590792Sgshapiro sm_allsignals(false); 313677349Sgshapiro 313777349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 313877349Sgshapiro save_errno = errno; 313977349Sgshapiro 314080785Sgshapiro /* block signals again and restore needed signals */ 314190792Sgshapiro sm_allsignals(true); 314280785Sgshapiro 314380785Sgshapiro /* For finis() events */ 314490792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 314580785Sgshapiro 314680785Sgshapiro#ifdef SIGUSR1 314780785Sgshapiro /* For debugging finis() */ 314890792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 314980785Sgshapiro#endif /* SIGUSR1 */ 315077349Sgshapiro 315177349Sgshapiro errno = save_errno; 315277349Sgshapiro if (LogLevel > 0) 315390792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 315490792Sgshapiro SaveArgv[0], sm_errstring(errno)); 315590792Sgshapiro finis(false, true, EX_OSFILE); 315690792Sgshapiro /* NOTREACHED */ 315777349Sgshapiro} 315890792Sgshapiro/* 315938032Speter** MYHOSTNAME -- return the name of this host. 316038032Speter** 316138032Speter** Parameters: 316238032Speter** hostbuf -- a place to return the name of this host. 316338032Speter** size -- the size of hostbuf. 316438032Speter** 316538032Speter** Returns: 316638032Speter** A list of aliases for this host. 316738032Speter** 316838032Speter** Side Effects: 316938032Speter** Adds numeric codes to $=w. 317038032Speter*/ 317138032Speter 317238032Speterstruct hostent * 317338032Spetermyhostname(hostbuf, size) 317438032Speter char hostbuf[]; 317538032Speter int size; 317638032Speter{ 317738032Speter register struct hostent *hp; 317838032Speter 317973188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 318090792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 318164562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 318290792Sgshapiro#if NETINET && NETINET6 318380785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 318480785Sgshapiro { 318580785Sgshapiro /* 318680785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 318780785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 318880785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 318980785Sgshapiro */ 319080785Sgshapiro 319180785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 319280785Sgshapiro } 319390792Sgshapiro#endif /* NETINET && NETINET6 */ 319438032Speter if (hp == NULL) 319538032Speter return NULL; 319638032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 319764562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 319864562Sgshapiro 319990792Sgshapiro#if NETINFO 320064562Sgshapiro if (strchr(hostbuf, '.') == NULL) 320138032Speter { 320264562Sgshapiro char *domainname; 320364562Sgshapiro 320464562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 320564562Sgshapiro "domain", '\0'); 320664562Sgshapiro if (domainname != NULL && 320764562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 320890792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 320938032Speter } 321090792Sgshapiro#endif /* NETINFO */ 321138032Speter 321238032Speter /* 321338032Speter ** If there is still no dot in the name, try looking for a 321438032Speter ** dotted alias. 321538032Speter */ 321638032Speter 321738032Speter if (strchr(hostbuf, '.') == NULL) 321838032Speter { 321938032Speter char **ha; 322038032Speter 322164562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 322238032Speter { 322338032Speter if (strchr(*ha, '.') != NULL) 322438032Speter { 322564562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 322638032Speter hostbuf[size - 1] = '\0'; 322738032Speter break; 322838032Speter } 322938032Speter } 323038032Speter } 323138032Speter 323238032Speter /* 323338032Speter ** If _still_ no dot, wait for a while and try again -- it is 323438032Speter ** possible that some service is starting up. This can result 323538032Speter ** in excessive delays if the system is badly configured, but 323638032Speter ** there really isn't a way around that, particularly given that 323738032Speter ** the config file hasn't been read at this point. 323838032Speter ** All in all, a bit of a mess. 323938032Speter */ 324038032Speter 324138032Speter if (strchr(hostbuf, '.') == NULL && 324290792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 324338032Speter { 324438032Speter sm_syslog(LOG_CRIT, NOQID, 324564562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 324664562Sgshapiro hostbuf); 324738032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 324838032Speter hostbuf); 324964562Sgshapiro (void) sleep(60); 325090792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 325138032Speter { 325238032Speter sm_syslog(LOG_ALERT, NOQID, 325364562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 325464562Sgshapiro hostbuf); 325538032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 325638032Speter hostbuf); 325738032Speter } 325838032Speter } 325964562Sgshapiro return hp; 326038032Speter} 326190792Sgshapiro/* 326238032Speter** ADDRCMP -- compare two host addresses 326338032Speter** 326438032Speter** Parameters: 326538032Speter** hp -- hostent structure for the first address 326638032Speter** ha -- actual first address 326738032Speter** sa -- second address 326838032Speter** 326938032Speter** Returns: 327038032Speter** 0 -- if ha and sa match 327138032Speter** else -- they don't match 327238032Speter*/ 327338032Speter 327464562Sgshapirostatic int 327538032Speteraddrcmp(hp, ha, sa) 327638032Speter struct hostent *hp; 327738032Speter char *ha; 327838032Speter SOCKADDR *sa; 327938032Speter{ 328090792Sgshapiro#if NETINET6 328190792Sgshapiro unsigned char *a; 328290792Sgshapiro#endif /* NETINET6 */ 328364562Sgshapiro 328438032Speter switch (sa->sa.sa_family) 328538032Speter { 328690792Sgshapiro#if NETINET 328738032Speter case AF_INET: 328838032Speter if (hp->h_addrtype == AF_INET) 328964562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 329038032Speter break; 329190792Sgshapiro#endif /* NETINET */ 329238032Speter 329390792Sgshapiro#if NETINET6 329464562Sgshapiro case AF_INET6: 329590792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 329664562Sgshapiro 329764562Sgshapiro /* Straight binary comparison */ 329864562Sgshapiro if (hp->h_addrtype == AF_INET6) 329964562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 330064562Sgshapiro 330164562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 330264562Sgshapiro if (hp->h_addrtype == AF_INET && 330364562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 330464562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 330564562Sgshapiro break; 330690792Sgshapiro#endif /* NETINET6 */ 330738032Speter } 330838032Speter return -1; 330938032Speter} 331090792Sgshapiro/* 331164562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 331238032Speter** 331338032Speter** Uses RFC1413 protocol to try to get info from the other end. 331438032Speter** 331538032Speter** Parameters: 331638032Speter** fd -- the descriptor 331790792Sgshapiro** may_be_forged -- an outage that is set to true if the 331838032Speter** forward lookup of RealHostName does not match 331990792Sgshapiro** RealHostAddr; set to false if they do match. 332038032Speter** 332138032Speter** Returns: 332238032Speter** The user@host information associated with this descriptor. 332338032Speter*/ 332438032Speter 332538032Speterstatic jmp_buf CtxAuthTimeout; 332638032Speter 332738032Speterstatic void 3328141858Sgshapiroauthtimeout(ignore) 3329141858Sgshapiro int ignore; 333038032Speter{ 333177349Sgshapiro /* 333277349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 333377349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 333477349Sgshapiro ** DOING. 333577349Sgshapiro */ 333677349Sgshapiro 333777349Sgshapiro errno = ETIMEDOUT; 333838032Speter longjmp(CtxAuthTimeout, 1); 333938032Speter} 334038032Speter 334138032Speterchar * 334238032Spetergetauthinfo(fd, may_be_forged) 334338032Speter int fd; 334438032Speter bool *may_be_forged; 334538032Speter{ 334690792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 334738032Speter SOCKADDR_LEN_T falen; 334838032Speter register char *volatile p = NULL; 334938032Speter SOCKADDR la; 335038032Speter SOCKADDR_LEN_T lalen; 335190792Sgshapiro#ifndef NO_GETSERVBYNAME 335238032Speter register struct servent *sp; 335390792Sgshapiro# if NETINET 335490792Sgshapiro static unsigned short port4 = 0; 335590792Sgshapiro# endif /* NETINET */ 335690792Sgshapiro# if NETINET6 335790792Sgshapiro static unsigned short port6 = 0; 335890792Sgshapiro# endif /* NETINET6 */ 335990792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 336038032Speter volatile int s; 336138032Speter int i = 0; 336290792Sgshapiro size_t len; 336390792Sgshapiro SM_EVENT *ev; 336438032Speter int nleft; 336538032Speter struct hostent *hp; 336638032Speter char *ostype = NULL; 336738032Speter char **ha; 336838032Speter char ibuf[MAXNAME + 1]; 3369110560Sgshapiro static char hbuf[MAXNAME + MAXAUTHINFO + 11]; 337038032Speter 337190792Sgshapiro *may_be_forged = false; 337238032Speter falen = sizeof RealHostAddr; 337338032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 337438032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 337538032Speter { 337664562Sgshapiro if (i < 0) 337764562Sgshapiro { 337864562Sgshapiro /* 337964562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 338064562Sgshapiro ** errno in this case, so a mis-report doesn't 338164562Sgshapiro ** happen later. 338264562Sgshapiro */ 338390792Sgshapiro 338464562Sgshapiro if (errno != ENOTSOCK) 338564562Sgshapiro return NULL; 338664562Sgshapiro errno = 0; 338764562Sgshapiro } 338890792Sgshapiro (void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName, 338990792Sgshapiro "@localhost"); 339038032Speter if (tTd(9, 1)) 339190792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 339238032Speter return hbuf; 339338032Speter } 339438032Speter 339538032Speter if (RealHostName == NULL) 339638032Speter { 339738032Speter /* translate that to a host name */ 339838032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 339938032Speter if (strlen(RealHostName) > MAXNAME) 340090792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 340138032Speter } 340238032Speter 340338032Speter /* cross check RealHostName with forward DNS lookup */ 340490792Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] != '[' && 340590792Sgshapiro RealHostName[0] != '[') 340638032Speter { 340780785Sgshapiro int family; 340880785Sgshapiro 340980785Sgshapiro family = RealHostAddr.sa.sa_family; 341090792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 341180785Sgshapiro /* 341280785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 341380785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 341480785Sgshapiro ** address(es) for addrcmp() to compare against 341580785Sgshapiro ** RealHostAddr. 341680785Sgshapiro ** 341780785Sgshapiro ** Actually, we only need to do this for systems 341880785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 341980785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 342080785Sgshapiro ** flag. A better fix to this problem is to add this 342180785Sgshapiro ** functionality to our stub getipnodebyname(). 342280785Sgshapiro */ 342380785Sgshapiro 342480785Sgshapiro if (family == AF_INET6 && 342580785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 342680785Sgshapiro family = AF_INET; 342790792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 342880785Sgshapiro 342938032Speter /* try to match the reverse against the forward lookup */ 343080785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 343138032Speter if (hp == NULL) 3432120256Sgshapiro { 3433132943Sgshapiro /* XXX: Could be a temporary error on forward lookup */ 343490792Sgshapiro *may_be_forged = true; 3435120256Sgshapiro } 343638032Speter else 343738032Speter { 343838032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 343990792Sgshapiro { 344038032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 344138032Speter break; 344290792Sgshapiro } 344338032Speter *may_be_forged = *ha == NULL; 344490792Sgshapiro#if NETINET6 344571345Sgshapiro freehostent(hp); 344671345Sgshapiro hp = NULL; 344790792Sgshapiro#endif /* NETINET6 */ 344838032Speter } 344938032Speter } 345038032Speter 345138032Speter if (TimeOuts.to_ident == 0) 345238032Speter goto noident; 345338032Speter 345438032Speter lalen = sizeof la; 345564562Sgshapiro switch (RealHostAddr.sa.sa_family) 345638032Speter { 345790792Sgshapiro#if NETINET 345864562Sgshapiro case AF_INET: 345964562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 346064562Sgshapiro lalen <= 0 || 346164562Sgshapiro la.sa.sa_family != AF_INET) 346264562Sgshapiro { 346364562Sgshapiro /* no ident info */ 346464562Sgshapiro goto noident; 346564562Sgshapiro } 346664562Sgshapiro port = RealHostAddr.sin.sin_port; 346738032Speter 346864562Sgshapiro /* create ident query */ 346990792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 347064562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 347164562Sgshapiro ntohs(la.sin.sin_port)); 347238032Speter 347364562Sgshapiro /* create local address */ 347464562Sgshapiro la.sin.sin_port = 0; 347538032Speter 347664562Sgshapiro /* create foreign address */ 347790792Sgshapiro# ifdef NO_GETSERVBYNAME 347838032Speter RealHostAddr.sin.sin_port = htons(113); 347990792Sgshapiro# else /* NO_GETSERVBYNAME */ 348090792Sgshapiro 348190792Sgshapiro /* 348290792Sgshapiro ** getservbyname() consumes about 5% of the time 348390792Sgshapiro ** when receiving a small message (almost all of the time 348490792Sgshapiro ** spent in this routine). 348590792Sgshapiro ** Hence we store the port in a static variable 348690792Sgshapiro ** to save this time. 348790792Sgshapiro ** The portnumber shouldn't change very often... 348890792Sgshapiro ** This code makes the assumption that the port number 348990792Sgshapiro ** is not 0. 349090792Sgshapiro */ 349190792Sgshapiro 349290792Sgshapiro if (port4 == 0) 349390792Sgshapiro { 349490792Sgshapiro sp = getservbyname("auth", "tcp"); 349590792Sgshapiro if (sp != NULL) 349690792Sgshapiro port4 = sp->s_port; 349790792Sgshapiro else 349890792Sgshapiro port4 = htons(113); 349990792Sgshapiro } 350090792Sgshapiro RealHostAddr.sin.sin_port = port4; 350164562Sgshapiro break; 350290792Sgshapiro# endif /* NO_GETSERVBYNAME */ 350390792Sgshapiro#endif /* NETINET */ 350438032Speter 350590792Sgshapiro#if NETINET6 350664562Sgshapiro case AF_INET6: 350764562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 350864562Sgshapiro lalen <= 0 || 350964562Sgshapiro la.sa.sa_family != AF_INET6) 351064562Sgshapiro { 351164562Sgshapiro /* no ident info */ 351264562Sgshapiro goto noident; 351364562Sgshapiro } 351464562Sgshapiro port = RealHostAddr.sin6.sin6_port; 351564562Sgshapiro 351664562Sgshapiro /* create ident query */ 351790792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 351864562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 351964562Sgshapiro ntohs(la.sin6.sin6_port)); 352064562Sgshapiro 352164562Sgshapiro /* create local address */ 352264562Sgshapiro la.sin6.sin6_port = 0; 352364562Sgshapiro 352464562Sgshapiro /* create foreign address */ 352590792Sgshapiro# ifdef NO_GETSERVBYNAME 352664562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 352790792Sgshapiro# else /* NO_GETSERVBYNAME */ 352890792Sgshapiro if (port6 == 0) 352990792Sgshapiro { 353090792Sgshapiro sp = getservbyname("auth", "tcp"); 353190792Sgshapiro if (sp != NULL) 353290792Sgshapiro port6 = sp->s_port; 353390792Sgshapiro else 353490792Sgshapiro port6 = htons(113); 353590792Sgshapiro } 353690792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 353764562Sgshapiro break; 353890792Sgshapiro# endif /* NO_GETSERVBYNAME */ 353990792Sgshapiro#endif /* NETINET6 */ 354064562Sgshapiro default: 354164562Sgshapiro /* no ident info */ 354264562Sgshapiro goto noident; 354364562Sgshapiro } 354464562Sgshapiro 354538032Speter s = -1; 354638032Speter if (setjmp(CtxAuthTimeout) != 0) 354738032Speter { 354838032Speter if (s >= 0) 354938032Speter (void) close(s); 355038032Speter goto noident; 355138032Speter } 355238032Speter 355338032Speter /* put a timeout around the whole thing */ 355490792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 355538032Speter 355638032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 355764562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 355838032Speter if (s < 0) 355938032Speter { 356090792Sgshapiro sm_clrevent(ev); 356138032Speter goto noident; 356238032Speter } 356364562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 356464562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 356538032Speter goto closeident; 356638032Speter 356738032Speter if (tTd(9, 10)) 356890792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 356938032Speter 357038032Speter /* send query */ 357138032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 357238032Speter goto closeident; 357338032Speter 357438032Speter /* get result */ 357538032Speter p = &ibuf[0]; 357638032Speter nleft = sizeof ibuf - 1; 357738032Speter while ((i = read(s, p, nleft)) > 0) 357838032Speter { 3579125820Sgshapiro char *s; 3580125820Sgshapiro 358138032Speter p += i; 358238032Speter nleft -= i; 358338032Speter *p = '\0'; 3584125820Sgshapiro if ((s = strchr(ibuf, '\n')) != NULL) 3585125820Sgshapiro { 3586125820Sgshapiro if (p > s + 1) 3587125820Sgshapiro { 3588125820Sgshapiro p = s + 1; 3589125820Sgshapiro *p = '\0'; 3590125820Sgshapiro } 359138032Speter break; 3592125820Sgshapiro } 3593125820Sgshapiro if (nleft <= 0) 3594125820Sgshapiro break; 359538032Speter } 359638032Speter (void) close(s); 359790792Sgshapiro sm_clrevent(ev); 359838032Speter if (i < 0 || p == &ibuf[0]) 359938032Speter goto noident; 360038032Speter 3601111823Sgshapiro if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r') 360238032Speter p--; 360338032Speter *++p = '\0'; 360438032Speter 360538032Speter if (tTd(9, 3)) 360690792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 360738032Speter 360838032Speter /* parse result */ 360938032Speter p = strchr(ibuf, ':'); 361038032Speter if (p == NULL) 361138032Speter { 361238032Speter /* malformed response */ 361338032Speter goto noident; 361438032Speter } 361538032Speter while (isascii(*++p) && isspace(*p)) 361638032Speter continue; 361790792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 361838032Speter { 361938032Speter /* presumably an error string */ 362038032Speter goto noident; 362138032Speter } 362238032Speter p += 6; 362338032Speter while (isascii(*p) && isspace(*p)) 362438032Speter p++; 362538032Speter if (*p++ != ':') 362638032Speter { 362738032Speter /* either useridxx or malformed response */ 362838032Speter goto noident; 362938032Speter } 363038032Speter 363138032Speter /* p now points to the OSTYPE field */ 363238032Speter while (isascii(*p) && isspace(*p)) 363338032Speter p++; 363438032Speter ostype = p; 363538032Speter p = strchr(p, ':'); 363638032Speter if (p == NULL) 363738032Speter { 363838032Speter /* malformed response */ 363938032Speter goto noident; 364038032Speter } 364138032Speter else 364238032Speter { 364338032Speter char *charset; 364438032Speter 364538032Speter *p = '\0'; 364638032Speter charset = strchr(ostype, ','); 364738032Speter if (charset != NULL) 364838032Speter *charset = '\0'; 364938032Speter } 365038032Speter 365138032Speter /* 1413 says don't do this -- but it's broken otherwise */ 365238032Speter while (isascii(*++p) && isspace(*p)) 365338032Speter continue; 365438032Speter 365538032Speter /* p now points to the authenticated name -- copy carefully */ 365690792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 365738032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 365838032Speter { 365990792Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf); 3660110560Sgshapiro cleanstrcpy(&hbuf[6], p, MAXAUTHINFO); 366138032Speter } 366238032Speter else 3663110560Sgshapiro cleanstrcpy(hbuf, p, MAXAUTHINFO); 366490792Sgshapiro len = strlen(hbuf); 366590792Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@", 366690792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 366738032Speter goto postident; 366838032Speter 366938032Spetercloseident: 367038032Speter (void) close(s); 367190792Sgshapiro sm_clrevent(ev); 367238032Speter 367338032Speternoident: 367464562Sgshapiro /* put back the original incoming port */ 367564562Sgshapiro switch (RealHostAddr.sa.sa_family) 367664562Sgshapiro { 367790792Sgshapiro#if NETINET 367864562Sgshapiro case AF_INET: 367964562Sgshapiro if (port > 0) 368064562Sgshapiro RealHostAddr.sin.sin_port = port; 368164562Sgshapiro break; 368290792Sgshapiro#endif /* NETINET */ 368364562Sgshapiro 368490792Sgshapiro#if NETINET6 368564562Sgshapiro case AF_INET6: 368664562Sgshapiro if (port > 0) 368764562Sgshapiro RealHostAddr.sin6.sin6_port = port; 368864562Sgshapiro break; 368990792Sgshapiro#endif /* NETINET6 */ 369064562Sgshapiro } 369164562Sgshapiro 369238032Speter if (RealHostName == NULL) 369338032Speter { 369438032Speter if (tTd(9, 1)) 369590792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 369638032Speter return NULL; 369738032Speter } 369890792Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf); 369938032Speter 370038032Speterpostident: 370190792Sgshapiro#if IP_SRCROUTE 370290792Sgshapiro# ifndef GET_IPOPT_DST 370390792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 370490792Sgshapiro# endif /* ! GET_IPOPT_DST */ 370538032Speter /* 370638032Speter ** Extract IP source routing information. 370738032Speter ** 370838032Speter ** Format of output for a connection from site a through b 370938032Speter ** through c to d: 371038032Speter ** loose: @site-c@site-b:site-a 371138032Speter ** strict: !@site-c@site-b:site-a 371238032Speter ** 371338032Speter ** o - pointer within ipopt_list structure. 371438032Speter ** q - pointer within ls/ss rr route data 371538032Speter ** p - pointer to hbuf 371638032Speter */ 371738032Speter 371838032Speter if (RealHostAddr.sa.sa_family == AF_INET) 371938032Speter { 372038032Speter SOCKOPT_LEN_T ipoptlen; 372138032Speter int j; 372290792Sgshapiro unsigned char *q; 372390792Sgshapiro unsigned char *o; 372438032Speter int l; 372564562Sgshapiro struct IPOPTION ipopt; 372638032Speter 372738032Speter ipoptlen = sizeof ipopt; 372838032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 372938032Speter (char *) &ipopt, &ipoptlen) < 0) 373038032Speter goto noipsr; 373138032Speter if (ipoptlen == 0) 373238032Speter goto noipsr; 373390792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 373490792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 373538032Speter { 373638032Speter switch (*o) 373738032Speter { 373864562Sgshapiro case IPOPT_EOL: 373938032Speter o = NULL; 374038032Speter break; 374138032Speter 374238032Speter case IPOPT_NOP: 374338032Speter o++; 374438032Speter break; 374538032Speter 374638032Speter case IPOPT_SSRR: 374738032Speter case IPOPT_LSRR: 374838032Speter /* 374938032Speter ** Source routing. 375038032Speter ** o[0] is the option type (loose/strict). 375138032Speter ** o[1] is the length of this option, 375238032Speter ** including option type and 375338032Speter ** length. 375438032Speter ** o[2] is the pointer into the route 375538032Speter ** data. 375638032Speter ** o[3] begins the route data. 375738032Speter */ 375838032Speter 375938032Speter p = &hbuf[strlen(hbuf)]; 376038032Speter l = sizeof hbuf - (hbuf - p) - 6; 376190792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 376290792Sgshapiro " [%s@%.*s", 376390792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 376490792Sgshapiro l > 240 ? 120 : l / 2, 376590792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 376638032Speter i = strlen(p); 376738032Speter p += i; 376838032Speter l -= strlen(p); 376938032Speter 377038032Speter j = o[1] / sizeof(struct in_addr) - 1; 377138032Speter 377238032Speter /* q skips length and router pointer to data */ 377338032Speter q = &o[3]; 377438032Speter for ( ; j >= 0; j--) 377538032Speter { 377664562Sgshapiro struct in_addr addr; 377764562Sgshapiro 377838032Speter memcpy(&addr, q, sizeof(addr)); 377990792Sgshapiro (void) sm_snprintf(p, 378090792Sgshapiro SPACELEFT(hbuf, p), 378190792Sgshapiro "%c%.*s", 378290792Sgshapiro j != 0 ? '@' : ':', 378390792Sgshapiro l > 240 ? 120 : 378490792Sgshapiro j == 0 ? l : l / 2, 378590792Sgshapiro inet_ntoa(addr)); 378638032Speter i = strlen(p); 378738032Speter p += i; 378838032Speter l -= i + 1; 378964562Sgshapiro q += sizeof(struct in_addr); 379038032Speter } 379138032Speter o += o[1]; 379238032Speter break; 379338032Speter 379438032Speter default: 379538032Speter /* Skip over option */ 379638032Speter o += o[1]; 379738032Speter break; 379838032Speter } 379938032Speter } 380090792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 380138032Speter goto postipsr; 380238032Speter } 380338032Speter 380438032Speternoipsr: 380590792Sgshapiro#endif /* IP_SRCROUTE */ 380638032Speter if (RealHostName != NULL && RealHostName[0] != '[') 380738032Speter { 380838032Speter p = &hbuf[strlen(hbuf)]; 380990792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 381090792Sgshapiro anynet_ntoa(&RealHostAddr)); 381138032Speter } 381238032Speter if (*may_be_forged) 381338032Speter { 381438032Speter p = &hbuf[strlen(hbuf)]; 381590792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 381690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 381790792Sgshapiro macid("{client_resolve}"), "FORGED"); 381838032Speter } 381938032Speter 382090792Sgshapiro#if IP_SRCROUTE 382138032Speterpostipsr: 382290792Sgshapiro#endif /* IP_SRCROUTE */ 382364562Sgshapiro 382464562Sgshapiro /* put back the original incoming port */ 382564562Sgshapiro switch (RealHostAddr.sa.sa_family) 382664562Sgshapiro { 382790792Sgshapiro#if NETINET 382864562Sgshapiro case AF_INET: 382964562Sgshapiro if (port > 0) 383064562Sgshapiro RealHostAddr.sin.sin_port = port; 383164562Sgshapiro break; 383290792Sgshapiro#endif /* NETINET */ 383364562Sgshapiro 383490792Sgshapiro#if NETINET6 383564562Sgshapiro case AF_INET6: 383664562Sgshapiro if (port > 0) 383764562Sgshapiro RealHostAddr.sin6.sin6_port = port; 383864562Sgshapiro break; 383990792Sgshapiro#endif /* NETINET6 */ 384064562Sgshapiro } 384164562Sgshapiro 384290792Sgshapiro if (tTd(9, 1)) 384390792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 384438032Speter return hbuf; 384538032Speter} 384690792Sgshapiro/* 384738032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 384838032Speter** 384938032Speter** Parameters: 385038032Speter** map -- a pointer to this map. 385138032Speter** name -- the (presumably unqualified) hostname. 385238032Speter** av -- unused -- for compatibility with other mapping 385338032Speter** functions. 385438032Speter** statp -- an exit status (out parameter) -- set to 385538032Speter** EX_TEMPFAIL if the name server is unavailable. 385638032Speter** 385738032Speter** Returns: 385838032Speter** The mapping, if found. 385938032Speter** NULL if no mapping found. 386038032Speter** 386138032Speter** Side Effects: 386238032Speter** Looks up the host specified in hbuf. If it is not 386338032Speter** the canonical name for that host, return the canonical 386438032Speter** name (unless MF_MATCHONLY is set, which will cause the 386538032Speter** status only to be returned). 386638032Speter*/ 386738032Speter 386838032Speterchar * 386938032Speterhost_map_lookup(map, name, av, statp) 387038032Speter MAP *map; 387138032Speter char *name; 387238032Speter char **av; 387338032Speter int *statp; 387438032Speter{ 387538032Speter register struct hostent *hp; 387690792Sgshapiro#if NETINET 387738032Speter struct in_addr in_addr; 387890792Sgshapiro#endif /* NETINET */ 387990792Sgshapiro#if NETINET6 388064562Sgshapiro struct in6_addr in6_addr; 388190792Sgshapiro#endif /* NETINET6 */ 388264562Sgshapiro char *cp, *ans = NULL; 388338032Speter register STAB *s; 388490792Sgshapiro time_t now; 388590792Sgshapiro#if NAMED_BIND 388690792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 388790792Sgshapiro int SM_NONVOLATILE retry = 0; 388890792Sgshapiro#endif /* NAMED_BIND */ 388938032Speter char hbuf[MAXNAME + 1]; 389038032Speter 389138032Speter /* 389238032Speter ** See if we have already looked up this name. If so, just 389390792Sgshapiro ** return it (unless expired). 389438032Speter */ 389538032Speter 389690792Sgshapiro now = curtime(); 389738032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 389890792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 389990792Sgshapiro s->s_namecanon.nc_exp >= now) 390038032Speter { 390138032Speter if (tTd(9, 1)) 390290792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 390390792Sgshapiro name, 390490792Sgshapiro s->s_namecanon.nc_cname == NULL 390538032Speter ? "NULL" 390638032Speter : s->s_namecanon.nc_cname); 390738032Speter errno = s->s_namecanon.nc_errno; 390873188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 390938032Speter *statp = s->s_namecanon.nc_stat; 391038032Speter if (*statp == EX_TEMPFAIL) 391138032Speter { 391238032Speter CurEnv->e_status = "4.4.3"; 391338032Speter message("851 %s: Name server timeout", 391438032Speter shortenstring(name, 33)); 391538032Speter } 391638032Speter if (*statp != EX_OK) 391738032Speter return NULL; 391838032Speter if (s->s_namecanon.nc_cname == NULL) 391938032Speter { 3920132943Sgshapiro syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d", 392164562Sgshapiro name, 392264562Sgshapiro s->s_namecanon.nc_errno, 392364562Sgshapiro s->s_namecanon.nc_herrno); 392438032Speter return NULL; 392538032Speter } 392638032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 392738032Speter cp = map_rewrite(map, name, strlen(name), NULL); 392838032Speter else 392938032Speter cp = map_rewrite(map, 393038032Speter s->s_namecanon.nc_cname, 393138032Speter strlen(s->s_namecanon.nc_cname), 393238032Speter av); 393338032Speter return cp; 393438032Speter } 393538032Speter 393638032Speter /* 393738032Speter ** If we are running without a regular network connection (usually 393838032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 393938032Speter ** lookups because those could try to connect to a server. 394038032Speter */ 394138032Speter 394264562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 394364562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 394438032Speter { 394538032Speter if (tTd(9, 1)) 394690792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 394738032Speter *statp = EX_TEMPFAIL; 394838032Speter return NULL; 394938032Speter } 395038032Speter 395138032Speter /* 395238032Speter ** If first character is a bracket, then it is an address 395338032Speter ** lookup. Address is copied into a temporary buffer to 395438032Speter ** strip the brackets and to preserve name if address is 395538032Speter ** unknown. 395638032Speter */ 395738032Speter 395864562Sgshapiro if (tTd(9, 1)) 395990792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 396090792Sgshapiro#if NAMED_BIND 396190792Sgshapiro if (map->map_timeout > 0) 396290792Sgshapiro { 396390792Sgshapiro retrans = _res.retrans; 396490792Sgshapiro _res.retrans = map->map_timeout; 396590792Sgshapiro } 396690792Sgshapiro if (map->map_retry > 0) 396790792Sgshapiro { 396890792Sgshapiro retry = _res.retry; 396990792Sgshapiro _res.retry = map->map_retry; 397090792Sgshapiro } 397190792Sgshapiro#endif /* NAMED_BIND */ 397290792Sgshapiro 397390792Sgshapiro /* set default TTL */ 397490792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 397538032Speter if (*name != '[') 397638032Speter { 397790792Sgshapiro int ttl; 397890792Sgshapiro 397990792Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof hbuf); 398090792Sgshapiro if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl)) 398190792Sgshapiro { 398264562Sgshapiro ans = hbuf; 398390792Sgshapiro if (ttl > 0) 398490792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 398590792Sgshapiro SM_DEFAULT_TTL); 398690792Sgshapiro } 398764562Sgshapiro } 398864562Sgshapiro else 398964562Sgshapiro { 399064562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 399171345Sgshapiro { 399271345Sgshapiro if (tTd(9, 1)) 399390792Sgshapiro sm_dprintf("FAILED\n"); 399464562Sgshapiro return NULL; 399571345Sgshapiro } 399664562Sgshapiro *cp = '\0'; 399764562Sgshapiro 399864562Sgshapiro hp = NULL; 399990792Sgshapiro#if NETINET 400064562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 400164562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 400264562Sgshapiro INADDRSZ, AF_INET); 400390792Sgshapiro#endif /* NETINET */ 400490792Sgshapiro#if NETINET6 400564562Sgshapiro if (hp == NULL && 400690792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 400764562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 400864562Sgshapiro IN6ADDRSZ, AF_INET6); 400990792Sgshapiro#endif /* NETINET6 */ 401064562Sgshapiro *cp = ']'; 401164562Sgshapiro 401264562Sgshapiro if (hp != NULL) 401338032Speter { 401464562Sgshapiro /* found a match -- copy out */ 401590792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 401690792Sgshapiro#if NETINET6 401790792Sgshapiro if (ans == hp->h_name) 401890792Sgshapiro { 401990792Sgshapiro static char n[MAXNAME + 1]; 402090792Sgshapiro 402190792Sgshapiro /* hp->h_name is about to disappear */ 402290792Sgshapiro (void) sm_strlcpy(n, ans, sizeof n); 402390792Sgshapiro ans = n; 402490792Sgshapiro } 402571345Sgshapiro freehostent(hp); 402671345Sgshapiro hp = NULL; 402790792Sgshapiro#endif /* NETINET6 */ 402838032Speter } 402964562Sgshapiro } 403090792Sgshapiro#if NAMED_BIND 403190792Sgshapiro if (map->map_timeout > 0) 403290792Sgshapiro _res.retrans = retrans; 403390792Sgshapiro if (map->map_retry > 0) 403490792Sgshapiro _res.retry = retry; 403590792Sgshapiro#endif /* NAMED_BIND */ 403638032Speter 403764562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 403838032Speter 403964562Sgshapiro /* Found an answer */ 404064562Sgshapiro if (ans != NULL) 404164562Sgshapiro { 404264562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 404390792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 404490792Sgshapiro sm_free(s->s_namecanon.nc_cname); 404590792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 404664562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 404764562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 404864562Sgshapiro else 404964562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 405071345Sgshapiro if (tTd(9, 1)) 405190792Sgshapiro sm_dprintf("FOUND %s\n", ans); 405264562Sgshapiro return cp; 405338032Speter } 405438032Speter 405564562Sgshapiro 405664562Sgshapiro /* No match found */ 405738032Speter s->s_namecanon.nc_errno = errno; 405890792Sgshapiro#if NAMED_BIND 405938032Speter s->s_namecanon.nc_herrno = h_errno; 406064562Sgshapiro if (tTd(9, 1)) 406190792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 406264562Sgshapiro switch (h_errno) 406338032Speter { 406464562Sgshapiro case TRY_AGAIN: 406564562Sgshapiro if (UseNameServer) 406664562Sgshapiro { 406764562Sgshapiro CurEnv->e_status = "4.4.3"; 406864562Sgshapiro message("851 %s: Name server timeout", 406964562Sgshapiro shortenstring(name, 33)); 407064562Sgshapiro } 407164562Sgshapiro *statp = EX_TEMPFAIL; 407264562Sgshapiro break; 407364562Sgshapiro 407464562Sgshapiro case HOST_NOT_FOUND: 407564562Sgshapiro case NO_DATA: 407664562Sgshapiro *statp = EX_NOHOST; 407764562Sgshapiro break; 407864562Sgshapiro 407964562Sgshapiro case NO_RECOVERY: 408064562Sgshapiro *statp = EX_SOFTWARE; 408164562Sgshapiro break; 408264562Sgshapiro 408364562Sgshapiro default: 408464562Sgshapiro *statp = EX_UNAVAILABLE; 408564562Sgshapiro break; 408638032Speter } 408790792Sgshapiro#else /* NAMED_BIND */ 408864562Sgshapiro if (tTd(9, 1)) 408990792Sgshapiro sm_dprintf("FAIL\n"); 409064562Sgshapiro *statp = EX_NOHOST; 409190792Sgshapiro#endif /* NAMED_BIND */ 409264562Sgshapiro s->s_namecanon.nc_stat = *statp; 409364562Sgshapiro return NULL; 409438032Speter} 409538032Speter/* 409690792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 409738032Speter** 409838032Speter** Parameters: 409990792Sgshapiro** map -- a pointer to this map. 410090792Sgshapiro** args -- argument string. 410138032Speter** 410238032Speter** Returns: 410390792Sgshapiro** true. 410438032Speter*/ 410538032Speter 410638032Speterbool 410738032Speterhost_map_init(map, args) 410838032Speter MAP *map; 410938032Speter char *args; 411038032Speter{ 411138032Speter register char *p = args; 411238032Speter 411338032Speter for (;;) 411438032Speter { 411538032Speter while (isascii(*p) && isspace(*p)) 411638032Speter p++; 411738032Speter if (*p != '-') 411838032Speter break; 411938032Speter switch (*++p) 412038032Speter { 412138032Speter case 'a': 412238032Speter map->map_app = ++p; 412338032Speter break; 412438032Speter 412538032Speter case 'T': 412638032Speter map->map_tapp = ++p; 412738032Speter break; 412838032Speter 412938032Speter case 'm': 413038032Speter map->map_mflags |= MF_MATCHONLY; 413138032Speter break; 413238032Speter 413338032Speter case 't': 413438032Speter map->map_mflags |= MF_NODEFER; 413538032Speter break; 413664562Sgshapiro 413764562Sgshapiro case 'S': /* only for consistency */ 413864562Sgshapiro map->map_spacesub = *++p; 413964562Sgshapiro break; 414064562Sgshapiro 414164562Sgshapiro case 'D': 414264562Sgshapiro map->map_mflags |= MF_DEFER; 414364562Sgshapiro break; 414490792Sgshapiro 414590792Sgshapiro case 'd': 414690792Sgshapiro { 414790792Sgshapiro char *h; 414890792Sgshapiro 414990792Sgshapiro while (isascii(*++p) && isspace(*p)) 415090792Sgshapiro continue; 415190792Sgshapiro h = strchr(p, ' '); 415290792Sgshapiro if (h != NULL) 415390792Sgshapiro *h = '\0'; 415490792Sgshapiro map->map_timeout = convtime(p, 's'); 415590792Sgshapiro if (h != NULL) 415690792Sgshapiro *h = ' '; 415790792Sgshapiro } 415890792Sgshapiro break; 415990792Sgshapiro 416090792Sgshapiro case 'r': 416190792Sgshapiro while (isascii(*++p) && isspace(*p)) 416290792Sgshapiro continue; 416390792Sgshapiro map->map_retry = atoi(p); 416490792Sgshapiro break; 416538032Speter } 416638032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 416738032Speter p++; 416838032Speter if (*p != '\0') 416938032Speter *p++ = '\0'; 417038032Speter } 417138032Speter if (map->map_app != NULL) 417238032Speter map->map_app = newstr(map->map_app); 417338032Speter if (map->map_tapp != NULL) 417438032Speter map->map_tapp = newstr(map->map_tapp); 417590792Sgshapiro return true; 417638032Speter} 417790792Sgshapiro 417864562Sgshapiro#if NETINET6 417964562Sgshapiro/* 418064562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 418164562Sgshapiro** 418264562Sgshapiro** Parameters: 418364562Sgshapiro** s6a -- a pointer to an in6_addr structure. 418464562Sgshapiro** dst -- buffer to store result in 418564562Sgshapiro** dst_len -- size of dst buffer 418664562Sgshapiro** 418764562Sgshapiro** Returns: 418864562Sgshapiro** A printable version of that structure. 418964562Sgshapiro*/ 419090792Sgshapiro 419164562Sgshapirochar * 419264562Sgshapiroanynet_ntop(s6a, dst, dst_len) 419364562Sgshapiro struct in6_addr *s6a; 419464562Sgshapiro char *dst; 419564562Sgshapiro size_t dst_len; 419664562Sgshapiro{ 419764562Sgshapiro register char *ap; 419864562Sgshapiro 419964562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 420064562Sgshapiro ap = (char *) inet_ntop(AF_INET, 420164562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 420264562Sgshapiro dst, dst_len); 420364562Sgshapiro else 420490792Sgshapiro { 420590792Sgshapiro char *d; 420690792Sgshapiro size_t sz; 420790792Sgshapiro 420890792Sgshapiro /* Save pointer to beginning of string */ 420990792Sgshapiro d = dst; 421090792Sgshapiro 421190792Sgshapiro /* Add IPv6: protocol tag */ 421290792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 421390792Sgshapiro if (sz >= dst_len) 421490792Sgshapiro return NULL; 421590792Sgshapiro dst += sz; 421690792Sgshapiro dst_len -= sz; 421764562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 421890792Sgshapiro 421990792Sgshapiro /* Restore pointer to beginning of string */ 422090792Sgshapiro if (ap != NULL) 422190792Sgshapiro ap = d; 422290792Sgshapiro } 422364562Sgshapiro return ap; 422464562Sgshapiro} 422590792Sgshapiro 422690792Sgshapiro/* 422790792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 422890792Sgshapiro** 422990792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 423090792Sgshapiro** 423190792Sgshapiro** Parameters: 423290792Sgshapiro** family -- address family 423390792Sgshapiro** src -- string 423490792Sgshapiro** dst -- destination address structure 423590792Sgshapiro** 423690792Sgshapiro** Returns: 423790792Sgshapiro** 1 if the address was valid 423890792Sgshapiro** 0 if the address wasn't parseable 423990792Sgshapiro** -1 if error 424090792Sgshapiro*/ 424190792Sgshapiro 424290792Sgshapiroint 424390792Sgshapiroanynet_pton(family, src, dst) 424490792Sgshapiro int family; 424590792Sgshapiro const char *src; 424690792Sgshapiro void *dst; 424790792Sgshapiro{ 424890792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 424990792Sgshapiro src += 5; 425090792Sgshapiro return inet_pton(family, src, dst); 425190792Sgshapiro} 425264562Sgshapiro#endif /* NETINET6 */ 425390792Sgshapiro/* 425438032Speter** ANYNET_NTOA -- convert a network address to printable form. 425538032Speter** 425638032Speter** Parameters: 425738032Speter** sap -- a pointer to a sockaddr structure. 425838032Speter** 425938032Speter** Returns: 426038032Speter** A printable version of that sockaddr. 426138032Speter*/ 426238032Speter 426338032Speter#ifdef USE_SOCK_STREAM 426438032Speter 426564562Sgshapiro# if NETLINK 426664562Sgshapiro# include <net/if_dl.h> 426764562Sgshapiro# endif /* NETLINK */ 426838032Speter 426938032Speterchar * 427038032Speteranynet_ntoa(sap) 427138032Speter register SOCKADDR *sap; 427238032Speter{ 427338032Speter register char *bp; 427438032Speter register char *ap; 427538032Speter int l; 427638032Speter static char buf[100]; 427738032Speter 427838032Speter /* check for null/zero family */ 427938032Speter if (sap == NULL) 428038032Speter return "NULLADDR"; 428138032Speter if (sap->sa.sa_family == 0) 428238032Speter return "0"; 428338032Speter 428438032Speter switch (sap->sa.sa_family) 428538032Speter { 428664562Sgshapiro# if NETUNIX 428738032Speter case AF_UNIX: 428864562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 428990792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]", 429090792Sgshapiro sap->sunix.sun_path); 429164562Sgshapiro else 429290792Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf); 429338032Speter return buf; 429464562Sgshapiro# endif /* NETUNIX */ 429538032Speter 429664562Sgshapiro# if NETINET 429738032Speter case AF_INET: 429864562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 429964562Sgshapiro# endif /* NETINET */ 430038032Speter 430164562Sgshapiro# if NETINET6 430264562Sgshapiro case AF_INET6: 430364562Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf); 430464562Sgshapiro if (ap != NULL) 430564562Sgshapiro return ap; 430664562Sgshapiro break; 430764562Sgshapiro# endif /* NETINET6 */ 430864562Sgshapiro 430964562Sgshapiro# if NETLINK 431038032Speter case AF_LINK: 431190792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[LINK: %s]", 431290792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 431338032Speter return buf; 431464562Sgshapiro# endif /* NETLINK */ 431538032Speter default: 431638032Speter /* this case is needed when nothing is #defined */ 431738032Speter /* in order to keep the switch syntactically correct */ 431838032Speter break; 431938032Speter } 432038032Speter 432138032Speter /* unknown family -- just dump bytes */ 432290792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 432338032Speter bp = &buf[strlen(buf)]; 432438032Speter ap = sap->sa.sa_data; 432538032Speter for (l = sizeof sap->sa.sa_data; --l >= 0; ) 432638032Speter { 432790792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 432890792Sgshapiro *ap++ & 0377); 432938032Speter bp += 3; 433038032Speter } 433138032Speter *--bp = '\0'; 433238032Speter return buf; 433338032Speter} 433490792Sgshapiro/* 433538032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 433638032Speter** 433738032Speter** Parameters: 433838032Speter** sap -- SOCKADDR pointer 433938032Speter** 434038032Speter** Returns: 434138032Speter** text representation of host name. 434238032Speter** 434338032Speter** Side Effects: 434438032Speter** none. 434538032Speter*/ 434638032Speter 434738032Speterchar * 434838032Speterhostnamebyanyaddr(sap) 434938032Speter register SOCKADDR *sap; 435038032Speter{ 435138032Speter register struct hostent *hp; 435264562Sgshapiro# if NAMED_BIND 435338032Speter int saveretry; 435464562Sgshapiro# endif /* NAMED_BIND */ 435564562Sgshapiro# if NETINET6 435664562Sgshapiro struct in6_addr in6_addr; 435764562Sgshapiro# endif /* NETINET6 */ 435838032Speter 435964562Sgshapiro# if NAMED_BIND 436038032Speter /* shorten name server timeout to avoid higher level timeouts */ 436138032Speter saveretry = _res.retry; 436264562Sgshapiro if (_res.retry * _res.retrans > 20) 436364562Sgshapiro _res.retry = 20 / _res.retrans; 436464562Sgshapiro# endif /* NAMED_BIND */ 436538032Speter 436638032Speter switch (sap->sa.sa_family) 436738032Speter { 436864562Sgshapiro# if NETINET 436938032Speter case AF_INET: 437038032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 437190792Sgshapiro INADDRSZ, AF_INET); 437238032Speter break; 437364562Sgshapiro# endif /* NETINET */ 437438032Speter 437564562Sgshapiro# if NETINET6 437664562Sgshapiro case AF_INET6: 437764562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 437890792Sgshapiro IN6ADDRSZ, AF_INET6); 437964562Sgshapiro break; 438064562Sgshapiro# endif /* NETINET6 */ 438164562Sgshapiro 438264562Sgshapiro# if NETISO 438338032Speter case AF_ISO: 438438032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 438590792Sgshapiro sizeof sap->siso.siso_addr, AF_ISO); 438638032Speter break; 438764562Sgshapiro# endif /* NETISO */ 438838032Speter 438964562Sgshapiro# if NETUNIX 439038032Speter case AF_UNIX: 439138032Speter hp = NULL; 439238032Speter break; 439364562Sgshapiro# endif /* NETUNIX */ 439438032Speter 439538032Speter default: 439690792Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data, 439790792Sgshapiro sap->sa.sa_family); 439838032Speter break; 439938032Speter } 440038032Speter 440164562Sgshapiro# if NAMED_BIND 440238032Speter _res.retry = saveretry; 440364562Sgshapiro# endif /* NAMED_BIND */ 440438032Speter 440564562Sgshapiro# if NETINET || NETINET6 440664562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 440764562Sgshapiro# if NETINET6 440864562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 440964562Sgshapiro# endif /* NETINET6 */ 441064562Sgshapiro# if NETINET 441164562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 441264562Sgshapiro# endif /* NETINET */ 441364562Sgshapiro ) 441471345Sgshapiro { 441571345Sgshapiro char *name; 441671345Sgshapiro 441790792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 441890792Sgshapiro# if NETINET6 441971345Sgshapiro if (name == hp->h_name) 442071345Sgshapiro { 442171345Sgshapiro static char n[MAXNAME + 1]; 442271345Sgshapiro 442371345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 442490792Sgshapiro (void) sm_strlcpy(n, name, sizeof n); 442571345Sgshapiro name = n; 442671345Sgshapiro } 442771345Sgshapiro freehostent(hp); 442890792Sgshapiro# endif /* NETINET6 */ 442971345Sgshapiro return name; 443071345Sgshapiro } 443164562Sgshapiro# endif /* NETINET || NETINET6 */ 443271345Sgshapiro 443390792Sgshapiro# if NETINET6 443471345Sgshapiro if (hp != NULL) 443571345Sgshapiro { 443671345Sgshapiro freehostent(hp); 443771345Sgshapiro hp = NULL; 443871345Sgshapiro } 443990792Sgshapiro# endif /* NETINET6 */ 444071345Sgshapiro 444164562Sgshapiro# if NETUNIX 444264562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 444338032Speter return "localhost"; 444464562Sgshapiro# endif /* NETUNIX */ 444538032Speter { 444638032Speter static char buf[203]; 444738032Speter 444890792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[%.200s]", 444990792Sgshapiro anynet_ntoa(sap)); 445038032Speter return buf; 445138032Speter } 445238032Speter} 445364562Sgshapiro#endif /* USE_SOCK_STREAM */ 4454