138032Speter/* 2261194Sgshapiro * Copyright (c) 1998-2007, 2009, 2010 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 15168515Sgshapiro#include "map.h" 1638032Speter 17266527SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.698 2013-11-22 20:51:55 ca Exp $") 1864562Sgshapiro 1938032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 2038032Speter# define USE_SOCK_STREAM 1 21363466Sgshapiro#endif 2238032Speter 2390792Sgshapiro#if defined(USE_SOCK_STREAM) 2464562Sgshapiro# if NETINET || NETINET6 2564562Sgshapiro# include <arpa/inet.h> 26363466Sgshapiro# endif 2738032Speter# if NAMED_BIND 2838032Speter# ifndef NO_DATA 2938032Speter# define NO_DATA NO_ADDRESS 30363466Sgshapiro# endif 3164562Sgshapiro# endif /* NAMED_BIND */ 3290792Sgshapiro#endif /* defined(USE_SOCK_STREAM) */ 3338032Speter 3490792Sgshapiro#if STARTTLS 35285229Sgshapiro# include <openssl/rand.h> 36363466Sgshapiro# if DANE 37363466Sgshapiro# include "tls.h" 38363466Sgshapiro# include "sm_resolve.h" 39363466Sgshapiro# endif 40363466Sgshapiro#endif 4138032Speter 42363466Sgshapiro#if NETINET6 43363466Sgshapiro# define FREEHOSTENT(h, s) \ 44363466Sgshapiro do \ 45363466Sgshapiro { \ 46363466Sgshapiro if ((h) != (s) && (h) != NULL) \ 47363466Sgshapiro { \ 48363466Sgshapiro freehostent((h)); \ 49363466Sgshapiro (h) = NULL; \ 50363466Sgshapiro } \ 51363466Sgshapiro } while (0) 52363466Sgshapiro#else 53363466Sgshapiro# define FREEHOSTENT(h, s) 54363466Sgshapiro#endif 55363466Sgshapiro 56157001Sgshapiro#include <sm/time.h> 5766494Sgshapiro 5890792Sgshapiro#if IP_SRCROUTE && NETINET 5990792Sgshapiro# include <netinet/in_systm.h> 6090792Sgshapiro# include <netinet/ip.h> 6190792Sgshapiro# if HAS_IN_H 6290792Sgshapiro# include <netinet/in.h> 6390792Sgshapiro# ifndef IPOPTION 6490792Sgshapiro# define IPOPTION ip_opts 6590792Sgshapiro# define IP_LIST ip_opts 6690792Sgshapiro# define IP_DST ip_dst 6790792Sgshapiro# endif /* ! IPOPTION */ 6890792Sgshapiro# else /* HAS_IN_H */ 6990792Sgshapiro# include <netinet/ip_var.h> 7090792Sgshapiro# ifndef IPOPTION 7190792Sgshapiro# define IPOPTION ipoption 7290792Sgshapiro# define IP_LIST ipopt_list 7390792Sgshapiro# define IP_DST ipopt_dst 7490792Sgshapiro# endif /* ! IPOPTION */ 7590792Sgshapiro# endif /* HAS_IN_H */ 7690792Sgshapiro#endif /* IP_SRCROUTE && NETINET */ 7738032Speter 7890792Sgshapiro#include <sm/fdset.h> 7938032Speter 80363466Sgshapiro#include <ratectrl.h> 81363466Sgshapiro 82168515Sgshapiro#define DAEMON_C 1 83168515Sgshapiro#include <daemon.h> 8464562Sgshapiro 85141858Sgshapirostatic void connecttimeout __P((int)); 8690792Sgshapirostatic int opendaemonsocket __P((DAEMON_T *, bool)); 8790792Sgshapirostatic unsigned short setupdaemon __P((SOCKADDR *)); 8890792Sgshapirostatic void getrequests_checkdiskspace __P((ENVELOPE *e)); 89141858Sgshapirostatic void setsockaddroptions __P((char *, DAEMON_T *)); 90141858Sgshapirostatic void printdaemonflags __P((DAEMON_T *)); 91141858Sgshapirostatic int addr_family __P((char *)); 92141858Sgshapirostatic int addrcmp __P((struct hostent *, char *, SOCKADDR *)); 93141858Sgshapirostatic void authtimeout __P((int)); 9464562Sgshapiro 9538032Speter/* 9638032Speter** DAEMON.C -- routines to use when running as a daemon. 9738032Speter** 9838032Speter** This entire file is highly dependent on the 4.2 BSD 9938032Speter** interprocess communication primitives. No attempt has 10038032Speter** been made to make this file portable to Version 7, 10138032Speter** Version 6, MPX files, etc. If you should try such a 10238032Speter** thing yourself, I recommend chucking the entire file 10338032Speter** and starting from scratch. Basic semantics are: 10438032Speter** 10538032Speter** getrequests(e) 10638032Speter** Opens a port and initiates a connection. 10738032Speter** Returns in a child. Must set InChannel and 10838032Speter** OutChannel appropriately. 10938032Speter** clrdaemon() 11038032Speter** Close any open files associated with getting 11138032Speter** the connection; this is used when running the queue, 11238032Speter** etc., to avoid having extra file descriptors during 11338032Speter** the queue run and to avoid confusing the network 11438032Speter** code (if it cares). 11590792Sgshapiro** makeconnection(host, port, mci, e, enough) 11638032Speter** Make a connection to the named host on the given 11790792Sgshapiro** port. Returns zero on success, else an exit status 11890792Sgshapiro** describing the error. 11938032Speter** host_map_lookup(map, hbuf, avp, pstat) 12038032Speter** Convert the entry in hbuf into a canonical form. 12138032Speter*/ 12264562Sgshapiro 12390792Sgshapirostatic int NDaemons = 0; /* actual number of daemons */ 12464562Sgshapiro 12590792Sgshapirostatic time_t NextDiskSpaceCheck = 0; 12664562Sgshapiro 12790792Sgshapiro/* 12838032Speter** GETREQUESTS -- open mail IPC port and get requests. 12938032Speter** 13038032Speter** Parameters: 13138032Speter** e -- the current envelope. 13238032Speter** 13338032Speter** Returns: 13464562Sgshapiro** pointer to flags. 13538032Speter** 13638032Speter** Side Effects: 13738032Speter** Waits until some interesting activity occurs. When 13838032Speter** it does, a child is created to process it, and the 13938032Speter** parent waits for completion. Return from this 14038032Speter** routine is always in the child. The file pointers 14138032Speter** "InChannel" and "OutChannel" should be set to point 14238032Speter** to the communication channel. 14390792Sgshapiro** May restart persistent queue runners if they have ended 14490792Sgshapiro** for some reason. 14538032Speter*/ 14638032Speter 14764562SgshapiroBITMAP256 * 14838032Spetergetrequests(e) 14938032Speter ENVELOPE *e; 15038032Speter{ 15138032Speter int t; 15264562Sgshapiro int idx, curdaemon = -1; 15364562Sgshapiro int i, olddaemon = 0; 15490792Sgshapiro#if XDEBUG 15538032Speter bool j_has_dot; 156363466Sgshapiro#endif 15742575Speter char status[MAXLINE]; 15864562Sgshapiro SOCKADDR sa; 159168515Sgshapiro SOCKADDR_LEN_T len = sizeof(sa); 16094334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 16194334Sgshapiro time_t lastrun; 162363466Sgshapiro#endif 163363466Sgshapiro#if NETUNIX 16442575Speter extern int ControlSocket; 165363466Sgshapiro#endif 16664562Sgshapiro extern ENVELOPE BlankEnvelope; 16738032Speter 16838032Speter 169125820Sgshapiro /* initialize data for function that generates queue ids */ 170125820Sgshapiro init_qid_alg(); 17190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 17238032Speter { 17364562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 17490792Sgshapiro Daemons[idx].d_firsttime = true; 17564562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 17638032Speter } 17771345Sgshapiro 17838032Speter /* 17938032Speter ** Try to actually open the connection. 18038032Speter */ 18138032Speter 18238032Speter if (tTd(15, 1)) 18364562Sgshapiro { 18490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 18571345Sgshapiro { 18690792Sgshapiro sm_dprintf("getrequests: daemon %s: port %d\n", 18790792Sgshapiro Daemons[idx].d_name, 18890792Sgshapiro ntohs(Daemons[idx].d_port)); 18971345Sgshapiro } 19064562Sgshapiro } 19138032Speter 19238032Speter /* get a socket for the SMTP connection */ 19390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 19490792Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true); 19538032Speter 19642575Speter if (opencontrolsocket() < 0) 19742575Speter sm_syslog(LOG_WARNING, NOQID, 19843730Speter "daemon could not open control socket %s: %s", 19990792Sgshapiro ControlSocketName, sm_errstring(errno)); 20042575Speter 20190792Sgshapiro /* If there are any queue runners released reapchild() co-ord's */ 20290792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 20338032Speter 20490792Sgshapiro /* write the pid to file, command line args to syslog */ 20564562Sgshapiro log_sendmail_pid(e); 20638032Speter 20790792Sgshapiro#if XDEBUG 20838032Speter { 20938032Speter char jbuf[MAXHOSTNAMELEN]; 21038032Speter 211168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), e); 21238032Speter j_has_dot = strchr(jbuf, '.') != NULL; 21338032Speter } 21490792Sgshapiro#endif /* XDEBUG */ 21538032Speter 21642575Speter /* Add parent process as first item */ 217132943Sgshapiro proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL); 21842575Speter 21938032Speter if (tTd(15, 1)) 22064562Sgshapiro { 22190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 222203004Sgshapiro sm_dprintf("getrequests: daemon %s: socket %d\n", 22364562Sgshapiro Daemons[idx].d_name, 22464562Sgshapiro Daemons[idx].d_socket); 22564562Sgshapiro } 22638032Speter 22738032Speter for (;;) 22838032Speter { 22938032Speter register pid_t pid; 23038032Speter auto SOCKADDR_LEN_T lotherend; 23190792Sgshapiro bool timedout = false; 23290792Sgshapiro bool control = false; 23364562Sgshapiro int save_errno; 23438032Speter int pipefd[2]; 23590792Sgshapiro time_t now; 23690792Sgshapiro#if STARTTLS 23766494Sgshapiro long seed; 238363466Sgshapiro#endif 23938032Speter 24038032Speter /* see if we are rejecting connections */ 24190792Sgshapiro (void) sm_blocksignal(SIGALRM); 242120256Sgshapiro CHECK_RESTART; 24364562Sgshapiro 24490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 24571345Sgshapiro { 24690792Sgshapiro /* 24790792Sgshapiro ** XXX do this call outside the loop? 24890792Sgshapiro ** no: refuse_connections may sleep(). 24990792Sgshapiro */ 25071345Sgshapiro 25190792Sgshapiro now = curtime(); 25290792Sgshapiro if (now < Daemons[idx].d_refuse_connections_until) 25364562Sgshapiro continue; 25490792Sgshapiro if (bitnset(D_DISABLE, Daemons[idx].d_flags)) 25590792Sgshapiro continue; 256168515Sgshapiro if (refuseconnections(e, idx, curdaemon == idx)) 25738032Speter { 25864562Sgshapiro if (Daemons[idx].d_socket >= 0) 25942575Speter { 26071345Sgshapiro /* close socket so peer fails quickly */ 26171345Sgshapiro (void) close(Daemons[idx].d_socket); 26271345Sgshapiro Daemons[idx].d_socket = -1; 26342575Speter } 26442575Speter 26542575Speter /* refuse connections for next 15 seconds */ 26690792Sgshapiro Daemons[idx].d_refuse_connections_until = now + 15; 26738032Speter } 26864562Sgshapiro else if (Daemons[idx].d_socket < 0 || 26964562Sgshapiro Daemons[idx].d_firsttime) 27042575Speter { 27190792Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel > 8) 27271345Sgshapiro sm_syslog(LOG_INFO, NOQID, 27371345Sgshapiro "accepting connections again for daemon %s", 27471345Sgshapiro Daemons[idx].d_name); 27564562Sgshapiro 27671345Sgshapiro /* arrange to (re)open the socket if needed */ 27790792Sgshapiro (void) opendaemonsocket(&Daemons[idx], false); 27890792Sgshapiro Daemons[idx].d_firsttime = false; 27942575Speter } 28038032Speter } 28138032Speter 28277349Sgshapiro /* May have been sleeping above, check again */ 283120256Sgshapiro CHECK_RESTART; 284132943Sgshapiro 28590792Sgshapiro getrequests_checkdiskspace(e); 28671345Sgshapiro 28790792Sgshapiro#if XDEBUG 28838032Speter /* check for disaster */ 28938032Speter { 29038032Speter char jbuf[MAXHOSTNAMELEN]; 29138032Speter 292168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), e); 29338032Speter if (!wordinclass(jbuf, 'w')) 29438032Speter { 29538032Speter dumpstate("daemon lost $j"); 29638032Speter sm_syslog(LOG_ALERT, NOQID, 29764562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 29838032Speter abort(); 29938032Speter } 30038032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 30138032Speter { 30238032Speter dumpstate("daemon $j lost dot"); 30338032Speter sm_syslog(LOG_ALERT, NOQID, 30464562Sgshapiro "daemon process $j lost dot; see syslog"); 30538032Speter abort(); 30638032Speter } 30738032Speter } 30890792Sgshapiro#endif /* XDEBUG */ 30938032Speter 31090792Sgshapiro#if 0 31138032Speter /* 31238032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 31338032Speter ** fix the SVr4 problem. But it seems to have gone away, 31438032Speter ** so is it worth doing this? 31538032Speter */ 31638032Speter 31742575Speter if (DaemonSocket >= 0 && 31890792Sgshapiro SetNonBlocking(DaemonSocket, false) < 0) 31938032Speter log an error here; 32090792Sgshapiro#endif /* 0 */ 32190792Sgshapiro (void) sm_releasesignal(SIGALRM); 32264562Sgshapiro 32338032Speter for (;;) 32438032Speter { 32590792Sgshapiro bool setproc = false; 32642575Speter int highest = -1; 32738032Speter fd_set readfds; 32838032Speter struct timeval timeout; 32938032Speter 330120256Sgshapiro CHECK_RESTART; 33138032Speter FD_ZERO(&readfds); 33290792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 33342575Speter { 33464562Sgshapiro /* wait for a connection */ 33564562Sgshapiro if (Daemons[idx].d_socket >= 0) 33664562Sgshapiro { 33771345Sgshapiro if (!setproc && 33871345Sgshapiro !bitnset(D_ETRNONLY, 33971345Sgshapiro Daemons[idx].d_flags)) 34064562Sgshapiro { 34190792Sgshapiro sm_setproctitle(true, e, 34264562Sgshapiro "accepting connections"); 34390792Sgshapiro setproc = true; 34464562Sgshapiro } 34564562Sgshapiro if (Daemons[idx].d_socket > highest) 34664562Sgshapiro highest = Daemons[idx].d_socket; 34790792Sgshapiro SM_FD_SET(Daemons[idx].d_socket, 34890792Sgshapiro &readfds); 34964562Sgshapiro } 35042575Speter } 35164562Sgshapiro 35290792Sgshapiro#if NETUNIX 35342575Speter if (ControlSocket >= 0) 35442575Speter { 35542575Speter if (ControlSocket > highest) 35642575Speter highest = ControlSocket; 35790792Sgshapiro SM_FD_SET(ControlSocket, &readfds); 35842575Speter } 35990792Sgshapiro#endif /* NETUNIX */ 36064562Sgshapiro 36177349Sgshapiro timeout.tv_sec = 5; 36238032Speter timeout.tv_usec = 0; 36338032Speter 36442575Speter t = select(highest + 1, FDSET_CAST &readfds, 36564562Sgshapiro NULL, NULL, &timeout); 36642575Speter 36777349Sgshapiro /* Did someone signal while waiting? */ 368120256Sgshapiro CHECK_RESTART; 36971345Sgshapiro 37090792Sgshapiro curdaemon = -1; 37190792Sgshapiro if (doqueuerun()) 37294334Sgshapiro { 37390792Sgshapiro (void) runqueue(true, false, false, false); 37494334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 37594334Sgshapiro lastrun = now; 376363466Sgshapiro#endif 37794334Sgshapiro } 37894334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 379157001Sgshapiro else if (CheckQueueRunners > 0 && QueueIntvl > 0 && 380157001Sgshapiro lastrun + QueueIntvl + CheckQueueRunners < now) 38194334Sgshapiro { 38271345Sgshapiro 38394334Sgshapiro /* 38494334Sgshapiro ** set lastrun unconditionally to avoid 38594334Sgshapiro ** calling checkqueuerunner() all the time. 38694334Sgshapiro ** That's also why we currently ignore the 38794334Sgshapiro ** result of the function call. 38894334Sgshapiro */ 38994334Sgshapiro 39094334Sgshapiro (void) checkqueuerunner(); 39194334Sgshapiro lastrun = now; 39294334Sgshapiro } 39394334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 39494334Sgshapiro 39542575Speter if (t <= 0) 39642575Speter { 39790792Sgshapiro timedout = true; 39842575Speter break; 39942575Speter } 40038032Speter 40190792Sgshapiro control = false; 40238032Speter errno = 0; 40364562Sgshapiro 40464562Sgshapiro /* look "round-robin" for an active socket */ 40590792Sgshapiro if ((idx = olddaemon + 1) >= NDaemons) 40664562Sgshapiro idx = 0; 40790792Sgshapiro for (i = 0; i < NDaemons; i++) 40842575Speter { 40964562Sgshapiro if (Daemons[idx].d_socket >= 0 && 41090792Sgshapiro SM_FD_ISSET(Daemons[idx].d_socket, 41190792Sgshapiro &readfds)) 41264562Sgshapiro { 41364562Sgshapiro lotherend = Daemons[idx].d_socksize; 41473188Sgshapiro memset(&RealHostAddr, '\0', 415168515Sgshapiro sizeof(RealHostAddr)); 41664562Sgshapiro t = accept(Daemons[idx].d_socket, 41764562Sgshapiro (struct sockaddr *)&RealHostAddr, 41864562Sgshapiro &lotherend); 41973188Sgshapiro 42073188Sgshapiro /* 42173188Sgshapiro ** If remote side closes before 42273188Sgshapiro ** accept() finishes, sockaddr 42373188Sgshapiro ** might not be fully filled in. 42473188Sgshapiro */ 42573188Sgshapiro 42673188Sgshapiro if (t >= 0 && 42773188Sgshapiro (lotherend == 0 || 428363466Sgshapiro#ifdef BSD4_4_SOCKADDR 42973188Sgshapiro RealHostAddr.sa.sa_len == 0 || 430363466Sgshapiro#endif 43173188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 43273188Sgshapiro { 43373188Sgshapiro (void) close(t); 43473188Sgshapiro t = -1; 43573188Sgshapiro errno = EINVAL; 43673188Sgshapiro } 43764562Sgshapiro olddaemon = curdaemon = idx; 43864562Sgshapiro break; 43964562Sgshapiro } 44090792Sgshapiro if (++idx >= NDaemons) 44164562Sgshapiro idx = 0; 44242575Speter } 44390792Sgshapiro#if NETUNIX 44464562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 44590792Sgshapiro SM_FD_ISSET(ControlSocket, &readfds)) 44642575Speter { 44742575Speter struct sockaddr_un sa_un; 44842575Speter 449168515Sgshapiro lotherend = sizeof(sa_un); 450168515Sgshapiro memset(&sa_un, '\0', sizeof(sa_un)); 45142575Speter t = accept(ControlSocket, 45242575Speter (struct sockaddr *)&sa_un, 45342575Speter &lotherend); 45473188Sgshapiro 45573188Sgshapiro /* 45673188Sgshapiro ** If remote side closes before 45773188Sgshapiro ** accept() finishes, sockaddr 45873188Sgshapiro ** might not be fully filled in. 45973188Sgshapiro */ 46073188Sgshapiro 46173188Sgshapiro if (t >= 0 && 46273188Sgshapiro (lotherend == 0 || 46373188Sgshapiro# ifdef BSD4_4_SOCKADDR 46473188Sgshapiro sa_un.sun_len == 0 || 465363466Sgshapiro# endif 46673188Sgshapiro sa_un.sun_family != AF_UNIX)) 46773188Sgshapiro { 46873188Sgshapiro (void) close(t); 46973188Sgshapiro t = -1; 47073188Sgshapiro errno = EINVAL; 47173188Sgshapiro } 47273188Sgshapiro if (t >= 0) 47390792Sgshapiro control = true; 47442575Speter } 47590792Sgshapiro#else /* NETUNIX */ 47671345Sgshapiro if (curdaemon == -1) 47771345Sgshapiro { 47871345Sgshapiro /* No daemon to service */ 47971345Sgshapiro continue; 48071345Sgshapiro } 48190792Sgshapiro#endif /* NETUNIX */ 48238032Speter if (t >= 0 || errno != EINTR) 48338032Speter break; 48438032Speter } 48542575Speter if (timedout) 48642575Speter { 48790792Sgshapiro timedout = false; 48842575Speter continue; 48942575Speter } 49064562Sgshapiro save_errno = errno; 49190792Sgshapiro (void) sm_blocksignal(SIGALRM); 49238032Speter if (t < 0) 49338032Speter { 49464562Sgshapiro errno = save_errno; 495132943Sgshapiro 496132943Sgshapiro /* let's ignore these temporary errors */ 497132943Sgshapiro if (save_errno == EINTR 498132943Sgshapiro#ifdef EAGAIN 499132943Sgshapiro || save_errno == EAGAIN 500363466Sgshapiro#endif 501132943Sgshapiro#ifdef ECONNABORTED 502132943Sgshapiro || save_errno == ECONNABORTED 503363466Sgshapiro#endif 504132943Sgshapiro#ifdef EWOULDBLOCK 505132943Sgshapiro || save_errno == EWOULDBLOCK 506363466Sgshapiro#endif 507132943Sgshapiro ) 508132943Sgshapiro continue; 509132943Sgshapiro 51038032Speter syserr("getrequests: accept"); 51138032Speter 512159609Sgshapiro if (curdaemon >= 0) 513159609Sgshapiro { 514159609Sgshapiro /* arrange to re-open socket next time around */ 515159609Sgshapiro (void) close(Daemons[curdaemon].d_socket); 516159609Sgshapiro Daemons[curdaemon].d_socket = -1; 51790792Sgshapiro#if SO_REUSEADDR_IS_BROKEN 518159609Sgshapiro /* 519159609Sgshapiro ** Give time for bound socket to be released. 520159609Sgshapiro ** This creates a denial-of-service if you can 521159609Sgshapiro ** force accept() to fail on affected systems. 522159609Sgshapiro */ 52364562Sgshapiro 524159609Sgshapiro Daemons[curdaemon].d_refuse_connections_until = 525159609Sgshapiro curtime() + 15; 52690792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */ 527159609Sgshapiro } 52838032Speter continue; 52938032Speter } 53038032Speter 53164562Sgshapiro if (!control) 53264562Sgshapiro { 53364562Sgshapiro /* set some daemon related macros */ 53464562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 53564562Sgshapiro { 53664562Sgshapiro case AF_UNSPEC: 53790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53890792Sgshapiro macid("{daemon_family}"), "unspec"); 53964562Sgshapiro break; 540285229Sgshapiro#if NETUNIX 54190792Sgshapiro case AF_UNIX: 54290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54390792Sgshapiro macid("{daemon_family}"), "local"); 54490792Sgshapiro break; 545363466Sgshapiro#endif 54690792Sgshapiro#if NETINET 54764562Sgshapiro case AF_INET: 54890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54990792Sgshapiro macid("{daemon_family}"), "inet"); 55064562Sgshapiro break; 551363466Sgshapiro#endif 55290792Sgshapiro#if NETINET6 55364562Sgshapiro case AF_INET6: 55490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55590792Sgshapiro macid("{daemon_family}"), "inet6"); 55664562Sgshapiro break; 557363466Sgshapiro#endif 55890792Sgshapiro#if NETISO 55964562Sgshapiro case AF_ISO: 56090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56190792Sgshapiro macid("{daemon_family}"), "iso"); 56264562Sgshapiro break; 563363466Sgshapiro#endif 56490792Sgshapiro#if NETNS 56564562Sgshapiro case AF_NS: 56690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56790792Sgshapiro macid("{daemon_family}"), "ns"); 56864562Sgshapiro break; 569363466Sgshapiro#endif 57090792Sgshapiro#if NETX25 57164562Sgshapiro case AF_CCITT: 57290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 57390792Sgshapiro macid("{daemon_family}"), "x.25"); 57464562Sgshapiro break; 575363466Sgshapiro#endif 57664562Sgshapiro } 57790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 57890792Sgshapiro macid("{daemon_name}"), 57990792Sgshapiro Daemons[curdaemon].d_name); 58064562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 58190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 58290792Sgshapiro macid("{daemon_flags}"), 58390792Sgshapiro Daemons[curdaemon].d_mflags); 58464562Sgshapiro else 58590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 58690792Sgshapiro macid("{daemon_flags}"), ""); 58764562Sgshapiro } 58864562Sgshapiro 58938032Speter /* 590132943Sgshapiro ** If connection rate is exceeded here, connection shall be 591132943Sgshapiro ** refused later by a new call after fork() by the 592132943Sgshapiro ** validate_connection() function. Closing the connection 593132943Sgshapiro ** at this point violates RFC 2821. 594132943Sgshapiro ** Do NOT remove this call, its side effects are needed. 595132943Sgshapiro */ 596132943Sgshapiro 597132943Sgshapiro connection_rate_check(&RealHostAddr, NULL); 598132943Sgshapiro 599132943Sgshapiro /* 60038032Speter ** Create a subprocess to process the mail. 60138032Speter */ 60238032Speter 60338032Speter if (tTd(15, 2)) 60490792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 60538032Speter 60638032Speter /* 60790792Sgshapiro ** Advance state of PRNG. 60890792Sgshapiro ** This is necessary because otherwise all child processes 60964562Sgshapiro ** will produce the same PRN sequence and hence the selection 61064562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 61164562Sgshapiro ** are not "really" random. 61264562Sgshapiro */ 61390792Sgshapiro#if STARTTLS 61490792Sgshapiro /* XXX get some better "random" data? */ 61566494Sgshapiro seed = get_random(); 61690792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 617168515Sgshapiro sizeof(NextDiskSpaceCheck)); 618168515Sgshapiro RAND_seed((void *) &now, sizeof(now)); 619168515Sgshapiro RAND_seed((void *) &seed, sizeof(seed)); 62090792Sgshapiro#else /* STARTTLS */ 62164562Sgshapiro (void) get_random(); 62290792Sgshapiro#endif /* STARTTLS */ 62364562Sgshapiro 62490792Sgshapiro#if NAMED_BIND 62564562Sgshapiro /* 626132943Sgshapiro ** Update MX records for FallbackMX. 62790792Sgshapiro ** Let's hope this is fast otherwise we screw up the 62890792Sgshapiro ** response time. 62990792Sgshapiro */ 63090792Sgshapiro 631132943Sgshapiro if (FallbackMX != NULL) 632132943Sgshapiro (void) getfallbackmxrr(FallbackMX); 63390792Sgshapiro#endif /* NAMED_BIND */ 63490792Sgshapiro 635110560Sgshapiro if (tTd(93, 100)) 636110560Sgshapiro { 637110560Sgshapiro /* don't fork, handle connection in this process */ 638110560Sgshapiro pid = 0; 63938032Speter pipefd[0] = pipefd[1] = -1; 640110560Sgshapiro } 641110560Sgshapiro else 642110560Sgshapiro { 643110560Sgshapiro /* 644110560Sgshapiro ** Create a pipe to keep the child from writing to 645110560Sgshapiro ** the socket until after the parent has closed 646110560Sgshapiro ** it. Otherwise the parent may hang if the child 647110560Sgshapiro ** has closed it first. 648110560Sgshapiro */ 64938032Speter 650110560Sgshapiro if (pipe(pipefd) < 0) 651110560Sgshapiro pipefd[0] = pipefd[1] = -1; 652110560Sgshapiro 653110560Sgshapiro (void) sm_blocksignal(SIGCHLD); 654110560Sgshapiro pid = fork(); 655110560Sgshapiro if (pid < 0) 65638032Speter { 657110560Sgshapiro syserr("daemon: cannot fork"); 658110560Sgshapiro if (pipefd[0] != -1) 659110560Sgshapiro { 660110560Sgshapiro (void) close(pipefd[0]); 661110560Sgshapiro (void) close(pipefd[1]); 662110560Sgshapiro } 663110560Sgshapiro (void) sm_releasesignal(SIGCHLD); 664110560Sgshapiro (void) sleep(10); 665110560Sgshapiro (void) close(t); 666110560Sgshapiro continue; 66738032Speter } 66838032Speter } 66990792Sgshapiro 67038032Speter if (pid == 0) 67138032Speter { 67238032Speter char *p; 67390792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 67438032Speter 67538032Speter /* 67638032Speter ** CHILD -- return to caller. 67738032Speter ** Collect verified idea of sending host. 67838032Speter ** Verify calling user id if possible here. 67938032Speter */ 68038032Speter 68177349Sgshapiro /* Reset global flags */ 68277349Sgshapiro RestartRequest = NULL; 68390792Sgshapiro RestartWorkGroup = false; 68477349Sgshapiro ShutdownRequest = NULL; 68577349Sgshapiro PendingSignal = 0; 68690792Sgshapiro CurrentPid = getpid(); 687132943Sgshapiro close_sendmail_pid(); 68877349Sgshapiro 68990792Sgshapiro (void) sm_releasesignal(SIGALRM); 69090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 69190792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 69290792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 69390792Sgshapiro (void) sm_signal(SIGTERM, intsig); 69477349Sgshapiro 69590792Sgshapiro /* turn on profiling */ 69690792Sgshapiro /* SM_PROF(0); */ 69790792Sgshapiro 69890792Sgshapiro /* 69990792Sgshapiro ** Initialize exception stack and default exception 70090792Sgshapiro ** handler for child process. 70190792Sgshapiro */ 70290792Sgshapiro 70390792Sgshapiro sm_exc_newthread(fatal_error); 70490792Sgshapiro 70564562Sgshapiro if (!control) 70664562Sgshapiro { 70790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 70890792Sgshapiro macid("{daemon_addr}"), 70990792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 710168515Sgshapiro (void) sm_snprintf(status, sizeof(status), "%d", 71164562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 71290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 71390792Sgshapiro macid("{daemon_port}"), status); 71464562Sgshapiro } 71564562Sgshapiro 71690792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 71764562Sgshapiro { 71864562Sgshapiro if (Daemons[idx].d_socket >= 0) 71964562Sgshapiro (void) close(Daemons[idx].d_socket); 72080785Sgshapiro Daemons[idx].d_socket = -1; 72164562Sgshapiro } 72242575Speter clrcontrol(); 72338032Speter 72464562Sgshapiro /* Avoid SMTP daemon actions if control command */ 72564562Sgshapiro if (control) 72664562Sgshapiro { 72764562Sgshapiro /* Add control socket process */ 72890792Sgshapiro proc_list_add(CurrentPid, 72990792Sgshapiro "console socket child", 730132943Sgshapiro PROC_CONTROL_CHILD, 0, -1, NULL); 73164562Sgshapiro } 73264562Sgshapiro else 73364562Sgshapiro { 73464562Sgshapiro proc_list_clear(); 73542575Speter 73690792Sgshapiro /* clean up background delivery children */ 73790792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 73890792Sgshapiro 73964562Sgshapiro /* Add parent process as first child item */ 74090792Sgshapiro proc_list_add(CurrentPid, "daemon child", 741132943Sgshapiro PROC_DAEMON_CHILD, 0, -1, NULL); 74264562Sgshapiro /* don't schedule queue runs if ETRN */ 74364562Sgshapiro QueueIntvl = 0; 744168515Sgshapiro 745168515Sgshapiro /* 746168515Sgshapiro ** Hack: override global variables if 747168515Sgshapiro ** the corresponding DaemonPortOption 748168515Sgshapiro ** is set. 749168515Sgshapiro */ 750147078Sgshapiro#if _FFR_SS_PER_DAEMON 751147078Sgshapiro if (Daemons[curdaemon].d_supersafe != 752168515Sgshapiro DPO_NOTSET) 753168515Sgshapiro SuperSafe = Daemons[curdaemon]. 754168515Sgshapiro d_supersafe; 755147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 756147078Sgshapiro if (Daemons[curdaemon].d_dm != DM_NOTSET) 757147078Sgshapiro set_delivery_mode( 758147078Sgshapiro Daemons[curdaemon].d_dm, e); 75938032Speter 760168515Sgshapiro if (Daemons[curdaemon].d_refuseLA != 761168515Sgshapiro DPO_NOTSET) 762168515Sgshapiro RefuseLA = Daemons[curdaemon]. 763168515Sgshapiro d_refuseLA; 764168515Sgshapiro if (Daemons[curdaemon].d_queueLA != DPO_NOTSET) 765168515Sgshapiro QueueLA = Daemons[curdaemon].d_queueLA; 766168515Sgshapiro if (Daemons[curdaemon].d_delayLA != DPO_NOTSET) 767168515Sgshapiro DelayLA = Daemons[curdaemon].d_delayLA; 768168515Sgshapiro if (Daemons[curdaemon].d_maxchildren != 769168515Sgshapiro DPO_NOTSET) 770168515Sgshapiro MaxChildren = Daemons[curdaemon]. 771168515Sgshapiro d_maxchildren; 772168515Sgshapiro 77390792Sgshapiro sm_setproctitle(true, e, "startup with %s", 77464562Sgshapiro anynet_ntoa(&RealHostAddr)); 77564562Sgshapiro } 77664562Sgshapiro 77738032Speter if (pipefd[0] != -1) 77838032Speter { 77938032Speter auto char c; 78038032Speter 78138032Speter /* 78238032Speter ** Wait for the parent to close the write end 78338032Speter ** of the pipe, which we will see as an EOF. 78438032Speter ** This guarantees that we won't write to the 78538032Speter ** socket until after the parent has closed 78638032Speter ** the pipe. 78738032Speter */ 78838032Speter 78938032Speter /* close the write end of the pipe */ 79038032Speter (void) close(pipefd[1]); 79138032Speter 79238032Speter /* we shouldn't be interrupted, but ... */ 79338032Speter while (read(pipefd[0], &c, 1) < 0 && 79438032Speter errno == EINTR) 79538032Speter continue; 79638032Speter (void) close(pipefd[0]); 79738032Speter } 79838032Speter 79964562Sgshapiro /* control socket processing */ 80064562Sgshapiro if (control) 80164562Sgshapiro { 80264562Sgshapiro control_command(t, e); 80364562Sgshapiro /* NOTREACHED */ 80464562Sgshapiro exit(EX_SOFTWARE); 80564562Sgshapiro } 80664562Sgshapiro 80738032Speter /* determine host name */ 80838032Speter p = hostnamebyanyaddr(&RealHostAddr); 80990792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 81038032Speter p[MAXNAME] = '\0'; 81138032Speter RealHostName = newstr(p); 81264562Sgshapiro if (RealHostName[0] == '[') 81364562Sgshapiro { 81490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 81590792Sgshapiro macid("{client_resolve}"), 81690792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 81764562Sgshapiro } 81864562Sgshapiro else 819132943Sgshapiro { 82090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 821132943Sgshapiro macid("{client_resolve}"), "OK"); 822132943Sgshapiro } 82390792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 82494334Sgshapiro markstats(e, NULL, STATS_CONNECT); 82538032Speter 82690792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 82790792Sgshapiro SM_TIME_DEFAULT, 82890792Sgshapiro (void *) &t, 829132943Sgshapiro SM_IO_RDONLY_B, 83090792Sgshapiro NULL)) == NULL || 83138032Speter (t = dup(t)) < 0 || 83290792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 83390792Sgshapiro SM_TIME_DEFAULT, 83490792Sgshapiro (void *) &t, 835132943Sgshapiro SM_IO_WRONLY_B, 83690792Sgshapiro NULL)) == NULL) 83738032Speter { 83890792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 83990792Sgshapiro t); 84090792Sgshapiro finis(false, true, EX_OK); 84138032Speter } 84290792Sgshapiro sm_io_automode(inchannel, outchannel); 84338032Speter 84438032Speter InChannel = inchannel; 84538032Speter OutChannel = outchannel; 84690792Sgshapiro DisConnected = false; 84738032Speter 848285229Sgshapiro#if _FFR_XCNCT 849285229Sgshapiro t = xconnect(inchannel); 850285229Sgshapiro if (t <= 0) 851285229Sgshapiro { 852285229Sgshapiro clrbitn(D_XCNCT, Daemons[curdaemon].d_flags); 853285229Sgshapiro clrbitn(D_XCNCT_M, Daemons[curdaemon].d_flags); 854285229Sgshapiro } 855285229Sgshapiro else 856285229Sgshapiro setbitn(t, Daemons[curdaemon].d_flags); 857244833Sgshapiro 858285229Sgshapiro#endif /* _FFR_XCNCT */ 859285229Sgshapiro 86090792Sgshapiro#if XLA 86138032Speter if (!xla_host_ok(RealHostName)) 86238032Speter { 86364562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 86490792Sgshapiro finis(false, true, EX_OK); 86538032Speter } 86690792Sgshapiro#endif /* XLA */ 86764562Sgshapiro /* find out name for interface of connection */ 86890792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 86990792Sgshapiro NULL), &sa.sa, &len) == 0) 87064562Sgshapiro { 87164562Sgshapiro p = hostnamebyanyaddr(&sa); 87264562Sgshapiro if (tTd(15, 9)) 87390792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 87490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 87590792Sgshapiro macid("{if_name}"), p); 87664562Sgshapiro 87790792Sgshapiro /* 87890792Sgshapiro ** Do this only if it is not the loopback 87990792Sgshapiro ** interface. 88090792Sgshapiro */ 88190792Sgshapiro 88264562Sgshapiro if (!isloopback(sa)) 88364562Sgshapiro { 88490792Sgshapiro char *addr; 88590792Sgshapiro char family[5]; 88690792Sgshapiro 88790792Sgshapiro addr = anynet_ntoa(&sa); 88890792Sgshapiro (void) sm_snprintf(family, 88990792Sgshapiro sizeof(family), 89090792Sgshapiro "%d", sa.sa.sa_family); 89190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 89290792Sgshapiro A_TEMP, 89390792Sgshapiro macid("{if_addr}"), addr); 89490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 89590792Sgshapiro A_TEMP, 89690792Sgshapiro macid("{if_family}"), family); 89764562Sgshapiro if (tTd(15, 7)) 89890792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 89990792Sgshapiro addr, family); 90064562Sgshapiro } 90164562Sgshapiro else 90264562Sgshapiro { 90390792Sgshapiro macdefine(&BlankEnvelope.e_macro, 90490792Sgshapiro A_PERM, 90590792Sgshapiro macid("{if_addr}"), NULL); 90690792Sgshapiro macdefine(&BlankEnvelope.e_macro, 90790792Sgshapiro A_PERM, 90890792Sgshapiro macid("{if_family}"), NULL); 90964562Sgshapiro } 91064562Sgshapiro } 91164562Sgshapiro else 91264562Sgshapiro { 91364562Sgshapiro if (tTd(15, 7)) 91490792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 91590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 91690792Sgshapiro macid("{if_name}"), NULL); 91790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 91890792Sgshapiro macid("{if_addr}"), NULL); 91990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 92090792Sgshapiro macid("{if_family}"), NULL); 92164562Sgshapiro } 92238032Speter break; 92338032Speter } 92438032Speter 92538032Speter /* parent -- keep track of children */ 92664562Sgshapiro if (control) 92764562Sgshapiro { 928168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 92990792Sgshapiro "control socket server child"); 930132943Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL); 93164562Sgshapiro } 93264562Sgshapiro else 93364562Sgshapiro { 934168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 93590792Sgshapiro "SMTP server child for %s", 93690792Sgshapiro anynet_ntoa(&RealHostAddr)); 937132943Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1, 938132943Sgshapiro &RealHostAddr); 93964562Sgshapiro } 94090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 94138032Speter 94238032Speter /* close the read end of the synchronization pipe */ 94338032Speter if (pipefd[0] != -1) 94464562Sgshapiro { 94538032Speter (void) close(pipefd[0]); 94664562Sgshapiro pipefd[0] = -1; 94764562Sgshapiro } 94838032Speter 94938032Speter /* close the port so that others will hang (for a while) */ 95038032Speter (void) close(t); 95138032Speter 95238032Speter /* release the child by closing the read end of the sync pipe */ 95338032Speter if (pipefd[1] != -1) 95464562Sgshapiro { 95538032Speter (void) close(pipefd[1]); 95664562Sgshapiro pipefd[1] = -1; 95764562Sgshapiro } 95838032Speter } 95990792Sgshapiro if (tTd(15, 2)) 96090792Sgshapiro sm_dprintf("getreq: returning\n"); 96164562Sgshapiro 96290792Sgshapiro#if MILTER 96390792Sgshapiro /* set the filters for this daemon */ 96490792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 96590792Sgshapiro { 96690792Sgshapiro for (i = 0; 967110560Sgshapiro (i < MAXFILTERS && 968110560Sgshapiro Daemons[curdaemon].d_inputfilters[i] != NULL); 96990792Sgshapiro i++) 97090792Sgshapiro { 97190792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 97290792Sgshapiro } 97390792Sgshapiro if (i < MAXFILTERS) 97490792Sgshapiro InputFilters[i] = NULL; 97590792Sgshapiro } 97690792Sgshapiro#endif /* MILTER */ 97764562Sgshapiro return &Daemons[curdaemon].d_flags; 97838032Speter} 97990792Sgshapiro 98090792Sgshapiro/* 98190792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 98290792Sgshapiro** 98390792Sgshapiro** Parameters: 98490792Sgshapiro** e -- envelope. 98590792Sgshapiro** 98690792Sgshapiro** Returns: 98790792Sgshapiro** none. 98890792Sgshapiro** 98990792Sgshapiro** Side Effects: 99090792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 99190792Sgshapiro*/ 99290792Sgshapiro 99390792Sgshapirostatic void 99490792Sgshapirogetrequests_checkdiskspace(e) 99590792Sgshapiro ENVELOPE *e; 99690792Sgshapiro{ 99790792Sgshapiro bool logged = false; 99890792Sgshapiro int idx; 99990792Sgshapiro time_t now; 100090792Sgshapiro 100190792Sgshapiro now = curtime(); 100290792Sgshapiro if (now < NextDiskSpaceCheck) 100390792Sgshapiro return; 100490792Sgshapiro 100590792Sgshapiro /* Check if there is available disk space in all queue groups. */ 100690792Sgshapiro if (!enoughdiskspace(0, NULL)) 100790792Sgshapiro { 100890792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 100990792Sgshapiro { 101090792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 101190792Sgshapiro continue; 101290792Sgshapiro 101390792Sgshapiro /* log only if not logged before */ 101490792Sgshapiro if (!logged) 101590792Sgshapiro { 101690792Sgshapiro if (LogLevel > 8) 101790792Sgshapiro sm_syslog(LOG_INFO, NOQID, 101890792Sgshapiro "rejecting new messages: min free: %ld", 101990792Sgshapiro MinBlocksFree); 102090792Sgshapiro sm_setproctitle(true, e, 102190792Sgshapiro "rejecting new messages: min free: %ld", 102290792Sgshapiro MinBlocksFree); 102390792Sgshapiro logged = true; 102490792Sgshapiro } 102590792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 102690792Sgshapiro } 102790792Sgshapiro } 102890792Sgshapiro else 102990792Sgshapiro { 103090792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 103190792Sgshapiro { 103290792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 103390792Sgshapiro continue; 103490792Sgshapiro 103590792Sgshapiro /* log only if not logged before */ 103690792Sgshapiro if (!logged) 103790792Sgshapiro { 103890792Sgshapiro if (LogLevel > 8) 103990792Sgshapiro sm_syslog(LOG_INFO, NOQID, 104090792Sgshapiro "accepting new messages (again)"); 104190792Sgshapiro logged = true; 104290792Sgshapiro } 104390792Sgshapiro 104490792Sgshapiro /* title will be set later */ 104590792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 104690792Sgshapiro } 104790792Sgshapiro } 104890792Sgshapiro 104990792Sgshapiro /* only check disk space once a minute */ 105090792Sgshapiro NextDiskSpaceCheck = now + 60; 105190792Sgshapiro} 105290792Sgshapiro 105390792Sgshapiro/* 105464562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 105538032Speter** 105664562Sgshapiro** Deals with setting all appropriate options. 105738032Speter** 105838032Speter** Parameters: 105964562Sgshapiro** d -- the structure for the daemon to open. 106038032Speter** firsttime -- set if this is the initial open. 106138032Speter** 106238032Speter** Returns: 106338032Speter** Size in bytes of the daemon socket addr. 106438032Speter** 106538032Speter** Side Effects: 106638032Speter** Leaves DaemonSocket set to the open socket. 106738032Speter** Exits if the socket cannot be created. 106838032Speter*/ 106938032Speter 107090792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 107138032Speter 107264562Sgshapirostatic int 107364562Sgshapiroopendaemonsocket(d, firsttime) 107490792Sgshapiro DAEMON_T *d; 107538032Speter bool firsttime; 107638032Speter{ 107738032Speter int on = 1; 107864562Sgshapiro int fdflags; 107964562Sgshapiro SOCKADDR_LEN_T socksize = 0; 108038032Speter int ntries = 0; 108164562Sgshapiro int save_errno; 108238032Speter 108338032Speter if (tTd(15, 2)) 108490792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 108538032Speter 108638032Speter do 108738032Speter { 108838032Speter if (ntries > 0) 108964562Sgshapiro (void) sleep(5); 109064562Sgshapiro if (firsttime || d->d_socket < 0) 109138032Speter { 1092285229Sgshapiro#if NETUNIX 109390792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 109490792Sgshapiro { 109590792Sgshapiro int rval; 109690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 109790792Sgshapiro 109890792Sgshapiro /* if not safe, don't use it */ 109990792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 110090792Sgshapiro RunAsUid, RunAsGid, 110190792Sgshapiro RunAsUserName, sff, 110290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 110390792Sgshapiro if (rval != 0) 110490792Sgshapiro { 110590792Sgshapiro save_errno = errno; 110690792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 110790792Sgshapiro d->d_name, 110890792Sgshapiro d->d_addr.sunix.sun_path); 110990792Sgshapiro goto fail; 111090792Sgshapiro } 111190792Sgshapiro 111290792Sgshapiro /* Don't try to overtake an existing socket */ 111390792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 111490792Sgshapiro } 1115285229Sgshapiro#endif /* NETUNIX */ 111664562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 111764562Sgshapiro SOCK_STREAM, 0); 111864562Sgshapiro if (d->d_socket < 0) 111938032Speter { 112064562Sgshapiro save_errno = errno; 112190792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 112290792Sgshapiro d->d_name); 112390792Sgshapiro fail: 112490792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 112590792Sgshapiro (!transienterror(save_errno) || 112690792Sgshapiro ntries >= MAXOPENTRIES - 1)) 112790792Sgshapiro { 112890792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 112990792Sgshapiro d->d_name); 113090792Sgshapiro setbitn(D_DISABLE, d->d_flags); 113190792Sgshapiro d->d_socket = -1; 113290792Sgshapiro return -1; 113390792Sgshapiro } 113438032Speter severe: 113538032Speter if (LogLevel > 0) 113638032Speter sm_syslog(LOG_ALERT, NOQID, 113790792Sgshapiro "daemon %s: problem creating SMTP socket", 113890792Sgshapiro d->d_name); 113964562Sgshapiro d->d_socket = -1; 114038032Speter continue; 114138032Speter } 114238032Speter 1143285229Sgshapiro if (!SM_FD_OK_SELECT(d->d_socket)) 1144110560Sgshapiro { 1145110560Sgshapiro save_errno = EINVAL; 1146110560Sgshapiro syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", 1147110560Sgshapiro d->d_name, d->d_socket); 1148110560Sgshapiro goto fail; 1149110560Sgshapiro } 1150110560Sgshapiro 115138032Speter /* turn on network debugging? */ 115238032Speter if (tTd(15, 101)) 115364562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 115438032Speter SO_DEBUG, (char *)&on, 1155168515Sgshapiro sizeof(on)); 115638032Speter 115764562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1158168515Sgshapiro SO_REUSEADDR, (char *)&on, sizeof(on)); 115964562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1160168515Sgshapiro SO_KEEPALIVE, (char *)&on, sizeof(on)); 116138032Speter 116290792Sgshapiro#ifdef SO_RCVBUF 116364562Sgshapiro if (d->d_tcprcvbufsize > 0) 116438032Speter { 116564562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 116638032Speter SO_RCVBUF, 116764562Sgshapiro (char *) &d->d_tcprcvbufsize, 116864562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 116964562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 117038032Speter } 117190792Sgshapiro#endif /* SO_RCVBUF */ 117290792Sgshapiro#ifdef SO_SNDBUF 117364562Sgshapiro if (d->d_tcpsndbufsize > 0) 117464562Sgshapiro { 117564562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 117664562Sgshapiro SO_SNDBUF, 117764562Sgshapiro (char *) &d->d_tcpsndbufsize, 117864562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 117964562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 118064562Sgshapiro } 118190792Sgshapiro#endif /* SO_SNDBUF */ 118238032Speter 118364562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 118464562Sgshapiro fcntl(d->d_socket, F_SETFD, 118564562Sgshapiro fdflags | FD_CLOEXEC) == -1) 118638032Speter { 118764562Sgshapiro save_errno = errno; 118864562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 118964562Sgshapiro d->d_name, 119064562Sgshapiro fdflags == -1 ? "get" : "set", 119190792Sgshapiro sm_errstring(save_errno)); 119264562Sgshapiro (void) close(d->d_socket); 119364562Sgshapiro goto severe; 119464562Sgshapiro } 119564562Sgshapiro 119664562Sgshapiro switch (d->d_addr.sa.sa_family) 119764562Sgshapiro { 1198285229Sgshapiro#ifdef NETUNIX 119990792Sgshapiro case AF_UNIX: 1200168515Sgshapiro socksize = sizeof(d->d_addr.sunix); 120190792Sgshapiro break; 1202363466Sgshapiro#endif 120390792Sgshapiro#if NETINET 120438032Speter case AF_INET: 1205168515Sgshapiro socksize = sizeof(d->d_addr.sin); 120638032Speter break; 1207363466Sgshapiro#endif 120838032Speter 120990792Sgshapiro#if NETINET6 121064562Sgshapiro case AF_INET6: 1211168515Sgshapiro socksize = sizeof(d->d_addr.sin6); 121264562Sgshapiro break; 1213363466Sgshapiro#endif 121464562Sgshapiro 121590792Sgshapiro#if NETISO 121638032Speter case AF_ISO: 1217168515Sgshapiro socksize = sizeof(d->d_addr.siso); 121838032Speter break; 1219363466Sgshapiro#endif 122038032Speter 122138032Speter default: 1222168515Sgshapiro socksize = sizeof(d->d_addr); 122338032Speter break; 122438032Speter } 122538032Speter 122664562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 122738032Speter { 122838032Speter /* probably another daemon already */ 122964562Sgshapiro save_errno = errno; 123064562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 123164562Sgshapiro d->d_name); 123264562Sgshapiro (void) close(d->d_socket); 123390792Sgshapiro goto fail; 123438032Speter } 123538032Speter } 123664562Sgshapiro if (!firsttime && 123764562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 123838032Speter { 123964562Sgshapiro save_errno = errno; 124064562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 124164562Sgshapiro d->d_name); 124264562Sgshapiro (void) close(d->d_socket); 124338032Speter goto severe; 124438032Speter } 124538032Speter return socksize; 124664562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 124764562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 124864562Sgshapiro d->d_name); 124964562Sgshapiro /* NOTREACHED */ 125038032Speter return -1; /* avoid compiler warning on IRIX */ 125138032Speter} 125290792Sgshapiro/* 125364562Sgshapiro** SETUPDAEMON -- setup socket for daemon 125464562Sgshapiro** 125564562Sgshapiro** Parameters: 125664562Sgshapiro** daemonaddr -- socket for daemon 125764562Sgshapiro** 125864562Sgshapiro** Returns: 125964562Sgshapiro** port number on which daemon should run 126064562Sgshapiro** 126164562Sgshapiro*/ 126290792Sgshapiro 126390792Sgshapirostatic unsigned short 126464562Sgshapirosetupdaemon(daemonaddr) 126564562Sgshapiro SOCKADDR *daemonaddr; 126664562Sgshapiro{ 126790792Sgshapiro unsigned short port; 126864562Sgshapiro 126964562Sgshapiro /* 127064562Sgshapiro ** Set up the address for the mailer. 127164562Sgshapiro */ 127264562Sgshapiro 127364562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 127464562Sgshapiro { 1275168515Sgshapiro memset(daemonaddr, '\0', sizeof(*daemonaddr)); 127690792Sgshapiro#if NETINET 127764562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 1278363466Sgshapiro#endif 127964562Sgshapiro } 128064562Sgshapiro 128164562Sgshapiro switch (daemonaddr->sa.sa_family) 128264562Sgshapiro { 128390792Sgshapiro#if NETINET 128464562Sgshapiro case AF_INET: 128564562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 1286182352Sgshapiro daemonaddr->sin.sin_addr.s_addr = 1287182352Sgshapiro LocalDaemon ? htonl(INADDR_LOOPBACK) : INADDR_ANY; 128864562Sgshapiro port = daemonaddr->sin.sin_port; 128964562Sgshapiro break; 129090792Sgshapiro#endif /* NETINET */ 129164562Sgshapiro 129290792Sgshapiro#if NETINET6 129364562Sgshapiro case AF_INET6: 129464562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 1295182352Sgshapiro daemonaddr->sin6.sin6_addr = 1296223067Sgshapiro (LocalDaemon && V6LoopbackAddrFound) ? 1297223067Sgshapiro in6addr_loopback : in6addr_any; 129864562Sgshapiro port = daemonaddr->sin6.sin6_port; 129964562Sgshapiro break; 130090792Sgshapiro#endif /* NETINET6 */ 130164562Sgshapiro 130264562Sgshapiro default: 130364562Sgshapiro /* unknown protocol */ 130464562Sgshapiro port = 0; 130564562Sgshapiro break; 130664562Sgshapiro } 130764562Sgshapiro if (port == 0) 130864562Sgshapiro { 130990792Sgshapiro#ifdef NO_GETSERVBYNAME 131064562Sgshapiro port = htons(25); 131190792Sgshapiro#else /* NO_GETSERVBYNAME */ 131264562Sgshapiro { 131364562Sgshapiro register struct servent *sp; 131464562Sgshapiro 131564562Sgshapiro sp = getservbyname("smtp", "tcp"); 131664562Sgshapiro if (sp == NULL) 131764562Sgshapiro { 131864562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 131964562Sgshapiro port = htons(25); 132064562Sgshapiro } 132164562Sgshapiro else 132264562Sgshapiro port = sp->s_port; 132364562Sgshapiro } 132490792Sgshapiro#endif /* NO_GETSERVBYNAME */ 132564562Sgshapiro } 132664562Sgshapiro 132764562Sgshapiro switch (daemonaddr->sa.sa_family) 132864562Sgshapiro { 132990792Sgshapiro#if NETINET 133064562Sgshapiro case AF_INET: 133164562Sgshapiro daemonaddr->sin.sin_port = port; 133264562Sgshapiro break; 1333363466Sgshapiro#endif 133464562Sgshapiro 133590792Sgshapiro#if NETINET6 133664562Sgshapiro case AF_INET6: 133764562Sgshapiro daemonaddr->sin6.sin6_port = port; 133864562Sgshapiro break; 1339363466Sgshapiro#endif 134064562Sgshapiro 134164562Sgshapiro default: 134264562Sgshapiro /* unknown protocol */ 134364562Sgshapiro break; 134464562Sgshapiro } 134590792Sgshapiro return port; 134664562Sgshapiro} 134790792Sgshapiro/* 134838032Speter** CLRDAEMON -- reset the daemon connection 134938032Speter** 135038032Speter** Parameters: 135138032Speter** none. 135238032Speter** 135338032Speter** Returns: 135438032Speter** none. 135538032Speter** 135638032Speter** Side Effects: 135738032Speter** releases any resources used by the passive daemon. 135838032Speter*/ 135938032Speter 136038032Spetervoid 136138032Speterclrdaemon() 136238032Speter{ 136364562Sgshapiro int i; 136464562Sgshapiro 136590792Sgshapiro for (i = 0; i < NDaemons; i++) 136664562Sgshapiro { 136764562Sgshapiro if (Daemons[i].d_socket >= 0) 136864562Sgshapiro (void) close(Daemons[i].d_socket); 136964562Sgshapiro Daemons[i].d_socket = -1; 137064562Sgshapiro } 137138032Speter} 137290792Sgshapiro 137390792Sgshapiro/* 137490792Sgshapiro** GETMODIFIERS -- get modifier flags 137590792Sgshapiro** 137690792Sgshapiro** Parameters: 137790792Sgshapiro** v -- the modifiers (input text line). 137890792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 137990792Sgshapiro** 138090792Sgshapiro** Returns: 138190792Sgshapiro** (xallocat()ed) string representation of modifiers. 138290792Sgshapiro** 138390792Sgshapiro** Side Effects: 138490792Sgshapiro** fills in modifiers. 138590792Sgshapiro*/ 138690792Sgshapiro 138790792Sgshapirochar * 138890792Sgshapirogetmodifiers(v, modifiers) 138990792Sgshapiro char *v; 139090792Sgshapiro BITMAP256 modifiers; 139190792Sgshapiro{ 139290792Sgshapiro int l; 139390792Sgshapiro char *h, *f, *flags; 139490792Sgshapiro 139590792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 139690792Sgshapiro l = 3 * strlen(v) + 3; 139790792Sgshapiro 139890792Sgshapiro /* is someone joking? */ 139990792Sgshapiro if (l < 0 || l > 256) 140090792Sgshapiro { 140190792Sgshapiro if (LogLevel > 2) 140290792Sgshapiro sm_syslog(LOG_ERR, NOQID, 140390792Sgshapiro "getmodifiers too long, ignored"); 140490792Sgshapiro return NULL; 140590792Sgshapiro } 140690792Sgshapiro flags = xalloc(l); 140790792Sgshapiro f = flags; 140890792Sgshapiro clrbitmap(modifiers); 140990792Sgshapiro for (h = v; *h != '\0'; h++) 141090792Sgshapiro { 141190792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 141290792Sgshapiro { 141390792Sgshapiro setbitn(*h, modifiers); 141490792Sgshapiro if (flags != f) 141590792Sgshapiro *flags++ = ' '; 141690792Sgshapiro *flags++ = *h; 141790792Sgshapiro if (isupper(*h)) 141890792Sgshapiro *flags++ = *h; 141990792Sgshapiro } 142090792Sgshapiro } 142190792Sgshapiro *flags++ = '\0'; 142290792Sgshapiro return f; 142390792Sgshapiro} 142490792Sgshapiro 142590792Sgshapiro/* 142690792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 142790792Sgshapiro** 142890792Sgshapiro** Parameters: 142990792Sgshapiro** flag -- the flag to test. 143090792Sgshapiro** 143190792Sgshapiro** Returns: 143290792Sgshapiro** true iff all daemons have set flag. 143390792Sgshapiro*/ 143490792Sgshapiro 143590792Sgshapirobool 143690792Sgshapirochkdaemonmodifiers(flag) 143790792Sgshapiro int flag; 143890792Sgshapiro{ 143990792Sgshapiro int i; 144090792Sgshapiro 144190792Sgshapiro for (i = 0; i < NDaemons; i++) 144290792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 144390792Sgshapiro return false; 144490792Sgshapiro return true; 144590792Sgshapiro} 144690792Sgshapiro 144790792Sgshapiro/* 144864562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 144938032Speter** 145038032Speter** Parameters: 145138032Speter** p -- the options line. 145264562Sgshapiro** d -- the daemon structure to fill in. 145338032Speter** 145438032Speter** Returns: 145538032Speter** none. 145638032Speter*/ 145738032Speter 145864562Sgshapirostatic void 145964562Sgshapirosetsockaddroptions(p, d) 1460141858Sgshapiro char *p; 146190792Sgshapiro DAEMON_T *d; 146238032Speter{ 146390792Sgshapiro#if NETISO 146471345Sgshapiro short portno; 1465363466Sgshapiro#endif 146671345Sgshapiro char *port = NULL; 146771345Sgshapiro char *addr = NULL; 146838032Speter 146990792Sgshapiro#if NETINET 147064562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 147164562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 1472363466Sgshapiro#endif 1473157001Sgshapiro#if _FFR_SS_PER_DAEMON 1474168515Sgshapiro d->d_supersafe = DPO_NOTSET; 1475363466Sgshapiro#endif 1476157001Sgshapiro d->d_dm = DM_NOTSET; 1477168515Sgshapiro d->d_refuseLA = DPO_NOTSET; 1478168515Sgshapiro d->d_queueLA = DPO_NOTSET; 1479168515Sgshapiro d->d_delayLA = DPO_NOTSET; 1480168515Sgshapiro d->d_maxchildren = DPO_NOTSET; 148164562Sgshapiro 148238032Speter while (p != NULL) 148338032Speter { 148438032Speter register char *f; 148538032Speter register char *v; 148638032Speter 1487363466Sgshapiro while (SM_ISSPACE(*p)) 148838032Speter p++; 148938032Speter if (*p == '\0') 149038032Speter break; 149138032Speter f = p; 149238032Speter p = strchr(p, ','); 149338032Speter if (p != NULL) 149438032Speter *p++ = '\0'; 149538032Speter v = strchr(f, '='); 149638032Speter if (v == NULL) 149738032Speter continue; 149838032Speter while (isascii(*++v) && isspace(*v)) 149938032Speter continue; 150038032Speter 150138032Speter switch (*f) 150238032Speter { 1503147078Sgshapiro case 'A': /* address */ 1504168515Sgshapiro#if !_FFR_DPO_CS 1505168515Sgshapiro case 'a': 1506363466Sgshapiro#endif 1507147078Sgshapiro addr = v; 1508147078Sgshapiro break; 1509147078Sgshapiro 1510168515Sgshapiro case 'c': 1511168515Sgshapiro d->d_maxchildren = atoi(v); 1512168515Sgshapiro break; 1513168515Sgshapiro 1514147078Sgshapiro case 'D': /* DeliveryMode */ 1515147078Sgshapiro switch (*v) 1516147078Sgshapiro { 1517147078Sgshapiro case SM_QUEUE: 1518147078Sgshapiro case SM_DEFER: 1519147078Sgshapiro case SM_DELIVER: 1520157001Sgshapiro case SM_FORK: 1521285229Sgshapiro#if _FFR_PROXY 1522285229Sgshapiro case SM_PROXY_REQ: 1523363466Sgshapiro#endif 1524147078Sgshapiro d->d_dm = *v; 1525147078Sgshapiro break; 1526147078Sgshapiro default: 1527147078Sgshapiro syserr("554 5.3.5 Unknown delivery mode %c", 1528147078Sgshapiro *v); 1529147078Sgshapiro break; 1530147078Sgshapiro } 1531147078Sgshapiro break; 1532147078Sgshapiro 1533168515Sgshapiro case 'd': /* delayLA */ 1534168515Sgshapiro d->d_delayLA = atoi(v); 1535168515Sgshapiro break; 1536168515Sgshapiro 153738032Speter case 'F': /* address family */ 1538168515Sgshapiro#if !_FFR_DPO_CS 1539168515Sgshapiro case 'f': 1540363466Sgshapiro#endif 154138032Speter if (isascii(*v) && isdigit(*v)) 154264562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 1543285229Sgshapiro#ifdef NETUNIX 154490792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 154590792Sgshapiro sm_strcasecmp(v, "local") == 0) 154690792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 1547363466Sgshapiro#endif 154890792Sgshapiro#if NETINET 154990792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 155064562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 1551363466Sgshapiro#endif 155290792Sgshapiro#if NETINET6 155390792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 155464562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 1555363466Sgshapiro#endif 155690792Sgshapiro#if NETISO 155790792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 155864562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 1559363466Sgshapiro#endif 156090792Sgshapiro#if NETNS 156190792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 156264562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 1563363466Sgshapiro#endif 156490792Sgshapiro#if NETX25 156590792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 156664562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 1567363466Sgshapiro#endif 156838032Speter else 156964562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 157064562Sgshapiro v); 157138032Speter break; 157238032Speter 157390792Sgshapiro#if MILTER 157490792Sgshapiro case 'I': 1575168515Sgshapiro# if !_FFR_DPO_CS 1576168515Sgshapiro case 'i': 1577363466Sgshapiro# endif 157890792Sgshapiro d->d_inputfilterlist = v; 157990792Sgshapiro break; 158090792Sgshapiro#endif /* MILTER */ 158190792Sgshapiro 158238032Speter case 'L': /* listen queue size */ 1583168515Sgshapiro#if !_FFR_DPO_CS 1584168515Sgshapiro case 'l': 1585363466Sgshapiro#endif 158664562Sgshapiro d->d_listenqueue = atoi(v); 158738032Speter break; 158838032Speter 158964562Sgshapiro case 'M': /* modifiers (flags) */ 1590168515Sgshapiro#if !_FFR_DPO_CS 1591168515Sgshapiro case 'm': 1592363466Sgshapiro#endif 159390792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 159464562Sgshapiro break; 159564562Sgshapiro 1596147078Sgshapiro case 'N': /* name */ 1597168515Sgshapiro#if !_FFR_DPO_CS 1598168515Sgshapiro case 'n': 1599363466Sgshapiro#endif 1600147078Sgshapiro d->d_name = v; 160138032Speter break; 160238032Speter 1603147078Sgshapiro case 'P': /* port */ 1604168515Sgshapiro#if !_FFR_DPO_CS 1605168515Sgshapiro case 'p': 1606363466Sgshapiro#endif 1607147078Sgshapiro port = v; 1608147078Sgshapiro break; 1609147078Sgshapiro 1610168515Sgshapiro case 'q': 1611168515Sgshapiro d->d_queueLA = atoi(v); 1612168515Sgshapiro break; 1613168515Sgshapiro 161438032Speter case 'R': /* receive buffer size */ 161564562Sgshapiro d->d_tcprcvbufsize = atoi(v); 161638032Speter break; 161738032Speter 1618168515Sgshapiro case 'r': 1619168515Sgshapiro d->d_refuseLA = atoi(v); 1620168515Sgshapiro break; 1621168515Sgshapiro 1622147078Sgshapiro case 'S': /* send buffer size */ 1623168515Sgshapiro#if !_FFR_DPO_CS 1624168515Sgshapiro case 's': 1625363466Sgshapiro#endif 1626147078Sgshapiro d->d_tcpsndbufsize = atoi(v); 162764562Sgshapiro break; 162864562Sgshapiro 1629147078Sgshapiro#if _FFR_SS_PER_DAEMON 1630147078Sgshapiro case 'T': /* SuperSafe */ 1631147078Sgshapiro if (tolower(*v) == 'i') 1632147078Sgshapiro d->d_supersafe = SAFE_INTERACTIVE; 1633147078Sgshapiro else if (tolower(*v) == 'p') 1634147078Sgshapiro# if MILTER 1635147078Sgshapiro d->d_supersafe = SAFE_REALLY_POSTMILTER; 1636147078Sgshapiro# else /* MILTER */ 1637147078Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1638147078Sgshapiro "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 1639147078Sgshapiro# endif /* MILTER */ 1640147078Sgshapiro else 1641147078Sgshapiro d->d_supersafe = atobool(v) ? SAFE_REALLY 1642147078Sgshapiro : SAFE_NO; 1643147078Sgshapiro break; 1644147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1645147078Sgshapiro 164638032Speter default: 164764562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 164864562Sgshapiro f); 164938032Speter } 165038032Speter } 165171345Sgshapiro 165271345Sgshapiro /* Check addr and port after finding family */ 165371345Sgshapiro if (addr != NULL) 165471345Sgshapiro { 165571345Sgshapiro switch (d->d_addr.sa.sa_family) 165671345Sgshapiro { 1657285229Sgshapiro#if NETUNIX 165890792Sgshapiro case AF_UNIX: 165990792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 166090792Sgshapiro { 166190792Sgshapiro errno = ENAMETOOLONG; 1662285229Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %ld", 1663285229Sgshapiro addr, 1664285229Sgshapiro (long) sizeof(d->d_addr.sunix.sun_path)); 166590792Sgshapiro break; 166690792Sgshapiro } 166790792Sgshapiro 166890792Sgshapiro /* file safety check done in opendaemonsocket() */ 166990792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 167090792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 167190792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 167290792Sgshapiro addr, 167390792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 167490792Sgshapiro break; 1675285229Sgshapiro#endif /* NETUNIX */ 167690792Sgshapiro#if NETINET 167771345Sgshapiro case AF_INET: 167871345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 167990792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 168090792Sgshapiro == INADDR_NONE)) 168171345Sgshapiro { 168271345Sgshapiro register struct hostent *hp; 168371345Sgshapiro 168471345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 168571345Sgshapiro if (hp == NULL) 168671345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 168771345Sgshapiro addr); 168871345Sgshapiro else 168971345Sgshapiro { 169071345Sgshapiro while (*(hp->h_addr_list) != NULL && 169171345Sgshapiro hp->h_addrtype != AF_INET) 169271345Sgshapiro hp->h_addr_list++; 169371345Sgshapiro if (*(hp->h_addr_list) == NULL) 169471345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 169571345Sgshapiro addr); 169671345Sgshapiro else 169771345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 169871345Sgshapiro *(hp->h_addr_list), 169971345Sgshapiro INADDRSZ); 1700363466Sgshapiro FREEHOSTENT(hp, NULL); 170171345Sgshapiro } 170271345Sgshapiro } 170371345Sgshapiro break; 170490792Sgshapiro#endif /* NETINET */ 170571345Sgshapiro 170690792Sgshapiro#if NETINET6 170771345Sgshapiro case AF_INET6: 170890792Sgshapiro if (anynet_pton(AF_INET6, addr, 170990792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 171071345Sgshapiro { 171171345Sgshapiro register struct hostent *hp; 171271345Sgshapiro 171371345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 171471345Sgshapiro if (hp == NULL) 171571345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 171671345Sgshapiro addr); 171771345Sgshapiro else 171871345Sgshapiro { 171971345Sgshapiro while (*(hp->h_addr_list) != NULL && 172071345Sgshapiro hp->h_addrtype != AF_INET6) 172171345Sgshapiro hp->h_addr_list++; 172271345Sgshapiro if (*(hp->h_addr_list) == NULL) 172371345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 172471345Sgshapiro addr); 172571345Sgshapiro else 172671345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 172771345Sgshapiro *(hp->h_addr_list), 172871345Sgshapiro IN6ADDRSZ); 1729363466Sgshapiro FREEHOSTENT(hp, NULL); 173071345Sgshapiro } 173171345Sgshapiro } 173271345Sgshapiro break; 173390792Sgshapiro#endif /* NETINET6 */ 173471345Sgshapiro 173571345Sgshapiro default: 173671345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 173771345Sgshapiro d->d_addr.sa.sa_family); 173871345Sgshapiro break; 173971345Sgshapiro } 174071345Sgshapiro } 174171345Sgshapiro 174271345Sgshapiro if (port != NULL) 174371345Sgshapiro { 174471345Sgshapiro switch (d->d_addr.sa.sa_family) 174571345Sgshapiro { 174690792Sgshapiro#if NETINET 174771345Sgshapiro case AF_INET: 174871345Sgshapiro if (isascii(*port) && isdigit(*port)) 174990792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 175090792Sgshapiro atoi((const char *) port)); 175171345Sgshapiro else 175271345Sgshapiro { 175390792Sgshapiro# ifdef NO_GETSERVBYNAME 175471345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 175571345Sgshapiro port); 175690792Sgshapiro# else /* NO_GETSERVBYNAME */ 175771345Sgshapiro register struct servent *sp; 175871345Sgshapiro 175971345Sgshapiro sp = getservbyname(port, "tcp"); 176071345Sgshapiro if (sp == NULL) 176171345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 176271345Sgshapiro port); 176371345Sgshapiro else 176471345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 176590792Sgshapiro# endif /* NO_GETSERVBYNAME */ 176671345Sgshapiro } 176771345Sgshapiro break; 176890792Sgshapiro#endif /* NETINET */ 176971345Sgshapiro 177090792Sgshapiro#if NETINET6 177171345Sgshapiro case AF_INET6: 177271345Sgshapiro if (isascii(*port) && isdigit(*port)) 177390792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 177490792Sgshapiro atoi(port)); 177571345Sgshapiro else 177671345Sgshapiro { 177790792Sgshapiro# ifdef NO_GETSERVBYNAME 177871345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 177971345Sgshapiro port); 178090792Sgshapiro# else /* NO_GETSERVBYNAME */ 178171345Sgshapiro register struct servent *sp; 178271345Sgshapiro 178371345Sgshapiro sp = getservbyname(port, "tcp"); 178471345Sgshapiro if (sp == NULL) 178571345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 178671345Sgshapiro port); 178771345Sgshapiro else 178871345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 178990792Sgshapiro# endif /* NO_GETSERVBYNAME */ 179071345Sgshapiro } 179171345Sgshapiro break; 179290792Sgshapiro#endif /* NETINET6 */ 179371345Sgshapiro 179490792Sgshapiro#if NETISO 179571345Sgshapiro case AF_ISO: 179671345Sgshapiro /* assume two byte transport selector */ 179771345Sgshapiro if (isascii(*port) && isdigit(*port)) 179890792Sgshapiro portno = htons((unsigned short) atoi(port)); 179971345Sgshapiro else 180071345Sgshapiro { 180190792Sgshapiro# ifdef NO_GETSERVBYNAME 180271345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 180371345Sgshapiro port); 180490792Sgshapiro# else /* NO_GETSERVBYNAME */ 180571345Sgshapiro register struct servent *sp; 180671345Sgshapiro 180771345Sgshapiro sp = getservbyname(port, "tcp"); 180871345Sgshapiro if (sp == NULL) 180971345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 181071345Sgshapiro port); 181171345Sgshapiro else 181271345Sgshapiro portno = sp->s_port; 181390792Sgshapiro# endif /* NO_GETSERVBYNAME */ 181471345Sgshapiro } 181571345Sgshapiro memmove(TSEL(&d->d_addr.siso), 181671345Sgshapiro (char *) &portno, 2); 181771345Sgshapiro break; 181890792Sgshapiro#endif /* NETISO */ 181971345Sgshapiro 182071345Sgshapiro default: 182171345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 182271345Sgshapiro d->d_addr.sa.sa_family); 182371345Sgshapiro break; 182471345Sgshapiro } 182571345Sgshapiro } 182638032Speter} 182790792Sgshapiro/* 182864562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 182938032Speter** 183038032Speter** Parameters: 183164562Sgshapiro** p -- the options line. 183264562Sgshapiro** 183364562Sgshapiro** Returns: 183490792Sgshapiro** true if successful, false otherwise. 183590792Sgshapiro** 183690792Sgshapiro** Side Effects: 183790792Sgshapiro** increments number of daemons. 183864562Sgshapiro*/ 183964562Sgshapiro 184090792Sgshapiro#define DEF_LISTENQUEUE 10 184190792Sgshapiro 184298841Sgshapirostruct dflags 184398841Sgshapiro{ 184498841Sgshapiro char *d_name; 184598841Sgshapiro int d_flag; 184698841Sgshapiro}; 184798841Sgshapiro 184898841Sgshapirostatic struct dflags DaemonFlags[] = 184998841Sgshapiro{ 185098841Sgshapiro { "AUTHREQ", D_AUTHREQ }, 185198841Sgshapiro { "BINDIF", D_BINDIF }, 185298841Sgshapiro { "CANONREQ", D_CANONREQ }, 185398841Sgshapiro { "IFNHELO", D_IFNHELO }, 185498841Sgshapiro { "FQMAIL", D_FQMAIL }, 185598841Sgshapiro { "FQRCPT", D_FQRCPT }, 185698841Sgshapiro { "SMTPS", D_SMTPS }, 185798841Sgshapiro { "UNQUALOK", D_UNQUALOK }, 185898841Sgshapiro { "NOAUTH", D_NOAUTH }, 185998841Sgshapiro { "NOCANON", D_NOCANON }, 186098841Sgshapiro { "NOETRN", D_NOETRN }, 186198841Sgshapiro { "NOTLS", D_NOTLS }, 186298841Sgshapiro { "ETRNONLY", D_ETRNONLY }, 186398841Sgshapiro { "OPTIONAL", D_OPTIONAL }, 186498841Sgshapiro { "DISABLE", D_DISABLE }, 186598841Sgshapiro { "ISSET", D_ISSET }, 186698841Sgshapiro { NULL, 0 } 186798841Sgshapiro}; 186898841Sgshapiro 186998841Sgshapirostatic void 187098841Sgshapiroprintdaemonflags(d) 187198841Sgshapiro DAEMON_T *d; 187298841Sgshapiro{ 187398841Sgshapiro register struct dflags *df; 187498841Sgshapiro bool first = true; 187598841Sgshapiro 187698841Sgshapiro for (df = DaemonFlags; df->d_name != NULL; df++) 187798841Sgshapiro { 187898841Sgshapiro if (!bitnset(df->d_flag, d->d_flags)) 187998841Sgshapiro continue; 188098841Sgshapiro if (first) 1881132943Sgshapiro sm_dprintf("<%s", df->d_name); 188298841Sgshapiro else 1883132943Sgshapiro sm_dprintf(",%s", df->d_name); 188498841Sgshapiro first = false; 188598841Sgshapiro } 188698841Sgshapiro if (!first) 1887132943Sgshapiro sm_dprintf(">"); 188898841Sgshapiro} 188998841Sgshapiro 189064562Sgshapirobool 189164562Sgshapirosetdaemonoptions(p) 189264562Sgshapiro register char *p; 189364562Sgshapiro{ 189490792Sgshapiro if (NDaemons >= MAXDAEMONS) 189590792Sgshapiro return false; 189690792Sgshapiro Daemons[NDaemons].d_socket = -1; 189790792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 189890792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 189990792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 190064562Sgshapiro 190190792Sgshapiro#if MILTER 190290792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 190390792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 1904363466Sgshapiro#endif 190590792Sgshapiro 190690792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 190790792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 190864562Sgshapiro else 190964562Sgshapiro { 191064562Sgshapiro char num[30]; 191164562Sgshapiro 1912168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Daemon%d", NDaemons); 191390792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 191464562Sgshapiro } 191564562Sgshapiro 191664562Sgshapiro if (tTd(37, 1)) 191764562Sgshapiro { 191890792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 191998841Sgshapiro printdaemonflags(&Daemons[NDaemons]); 192090792Sgshapiro sm_dprintf("\n"); 192164562Sgshapiro } 192290792Sgshapiro ++NDaemons; 192390792Sgshapiro return true; 192464562Sgshapiro} 192590792Sgshapiro/* 192664562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 192764562Sgshapiro** 192864562Sgshapiro** Parameters: 192964562Sgshapiro** none 193064562Sgshapiro** 193164562Sgshapiro** Returns: 193264562Sgshapiro** none 193364562Sgshapiro** 193464562Sgshapiro** Side Effects: 193564562Sgshapiro** initializes structure for one daemon. 193664562Sgshapiro*/ 193790792Sgshapiro 193864562Sgshapirovoid 193964562Sgshapiroinitdaemon() 194064562Sgshapiro{ 194190792Sgshapiro if (NDaemons == 0) 194264562Sgshapiro { 194390792Sgshapiro Daemons[NDaemons].d_socket = -1; 194490792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 194590792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 194690792Sgshapiro NDaemons = 1; 194764562Sgshapiro } 194864562Sgshapiro} 194990792Sgshapiro/* 195064562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 195164562Sgshapiro** 195264562Sgshapiro** Parameters: 195364562Sgshapiro** p -- the options line. 195464562Sgshapiro** 195564562Sgshapiro** Returns: 195664562Sgshapiro** none. 195764562Sgshapiro*/ 195864562Sgshapiro 195990792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 196064562Sgshapiro 196164562Sgshapirovoid 196264562Sgshapirosetclientoptions(p) 196364562Sgshapiro register char *p; 196464562Sgshapiro{ 196590792Sgshapiro int family; 196690792Sgshapiro DAEMON_T d; 196764562Sgshapiro 1968168515Sgshapiro memset(&d, '\0', sizeof(d)); 196964562Sgshapiro setsockaddroptions(p, &d); 197064562Sgshapiro 197164562Sgshapiro /* grab what we need */ 197290792Sgshapiro family = d.d_addr.sa.sa_family; 197390792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 197490792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 197590792Sgshapiro if (d.d_name != NULL) 197690792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 197764562Sgshapiro else 197890792Sgshapiro { 197990792Sgshapiro char num[30]; 198090792Sgshapiro 1981168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Client%d", family); 198290792Sgshapiro ClientSettings[family].d_name = newstr(num); 198390792Sgshapiro } 198464562Sgshapiro} 198590792Sgshapiro/* 198664562Sgshapiro** ADDR_FAMILY -- determine address family from address 198764562Sgshapiro** 198864562Sgshapiro** Parameters: 198964562Sgshapiro** addr -- the string representation of the address 199064562Sgshapiro** 199164562Sgshapiro** Returns: 199264562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 199364562Sgshapiro** 199464562Sgshapiro** Side Effects: 199564562Sgshapiro** none. 199664562Sgshapiro*/ 199764562Sgshapiro 199864562Sgshapirostatic int 199964562Sgshapiroaddr_family(addr) 200064562Sgshapiro char *addr; 200164562Sgshapiro{ 200290792Sgshapiro#if NETINET6 200364562Sgshapiro SOCKADDR clt_addr; 2004363466Sgshapiro#endif 200564562Sgshapiro 200690792Sgshapiro#if NETINET 200764562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 200864562Sgshapiro { 200964562Sgshapiro if (tTd(16, 9)) 201090792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 201164562Sgshapiro return AF_INET; 201264562Sgshapiro } 201390792Sgshapiro#endif /* NETINET */ 201490792Sgshapiro#if NETINET6 201590792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 201664562Sgshapiro { 201764562Sgshapiro if (tTd(16, 9)) 201890792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 201964562Sgshapiro return AF_INET6; 202064562Sgshapiro } 202190792Sgshapiro#endif /* NETINET6 */ 2022285229Sgshapiro#if NETUNIX 202390792Sgshapiro if (*addr == '/') 202490792Sgshapiro { 202590792Sgshapiro if (tTd(16, 9)) 202690792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 202790792Sgshapiro return AF_UNIX; 202890792Sgshapiro } 2029285229Sgshapiro#endif /* NETUNIX */ 203064562Sgshapiro if (tTd(16, 9)) 203190792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 203264562Sgshapiro return AF_UNSPEC; 203364562Sgshapiro} 203490792Sgshapiro 203590792Sgshapiro/* 203690792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 203790792Sgshapiro** 203890792Sgshapiro** Parameters: 203990792Sgshapiro** flag -- the flag to test. 204090792Sgshapiro** 204190792Sgshapiro** Returns: 204290792Sgshapiro** true iff all configured clients have set the flag. 204390792Sgshapiro*/ 204490792Sgshapiro 204590792Sgshapirobool 204690792Sgshapirochkclientmodifiers(flag) 204790792Sgshapiro int flag; 204890792Sgshapiro{ 204990792Sgshapiro int i; 205090792Sgshapiro bool flagisset; 205190792Sgshapiro 205290792Sgshapiro flagisset = false; 205390792Sgshapiro for (i = 0; i < AF_MAX; i++) 205490792Sgshapiro { 205590792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 205690792Sgshapiro { 205790792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 205890792Sgshapiro return false; 205990792Sgshapiro flagisset = true; 206090792Sgshapiro } 206190792Sgshapiro } 206290792Sgshapiro return flagisset; 206390792Sgshapiro} 206490792Sgshapiro 206590792Sgshapiro#if MILTER 206690792Sgshapiro/* 2067285229Sgshapiro** SETUP_DAEMON_MILTERS -- Parse per-socket filters 206890792Sgshapiro** 206990792Sgshapiro** Parameters: 207090792Sgshapiro** none 207190792Sgshapiro** 207290792Sgshapiro** Returns: 207390792Sgshapiro** none 207490792Sgshapiro*/ 207590792Sgshapiro 207690792Sgshapirovoid 207790792Sgshapirosetup_daemon_milters() 207890792Sgshapiro{ 207990792Sgshapiro int idx; 208090792Sgshapiro 208190792Sgshapiro if (OpMode == MD_SMTP) 208290792Sgshapiro { 208390792Sgshapiro /* no need to configure the daemons */ 208490792Sgshapiro return; 208590792Sgshapiro } 208690792Sgshapiro 208790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 208890792Sgshapiro { 208990792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 209090792Sgshapiro { 209190792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 209290792Sgshapiro Daemons[idx].d_inputfilters, 209390792Sgshapiro MAXFILTERS); 209490792Sgshapiro } 209590792Sgshapiro } 209690792Sgshapiro} 209790792Sgshapiro#endif /* MILTER */ 209890792Sgshapiro/* 209964562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 210064562Sgshapiro** 210164562Sgshapiro** Parameters: 210238032Speter** host -- the name of the host. 210338032Speter** port -- the port number to connect to. 210438032Speter** mci -- a pointer to the mail connection information 210538032Speter** structure to be filled in. 210638032Speter** e -- the current envelope. 210790792Sgshapiro** enough -- time at which to stop further connection attempts. 210890792Sgshapiro** (0 means no limit) 210938032Speter** 211038032Speter** Returns: 211138032Speter** An exit code telling whether the connection could be 211238032Speter** made and if not why not. 211338032Speter** 211438032Speter** Side Effects: 211538032Speter** none. 211638032Speter*/ 211738032Speter 211838032Speterstatic jmp_buf CtxConnectTimeout; 211938032Speter 212038032SpeterSOCKADDR CurHostAddr; /* address of current host */ 212138032Speter 212238032Speterint 2123363466Sgshapiromakeconnection(host, port, mci, e, enough 2124363466Sgshapiro#if DANE 2125363466Sgshapiro , ptlsa_flags 2126363466Sgshapiro#endif 2127363466Sgshapiro ) 212838032Speter char *host; 212990792Sgshapiro volatile unsigned int port; 213038032Speter register MCI *mci; 213138032Speter ENVELOPE *e; 213290792Sgshapiro time_t enough; 2133363466Sgshapiro#if DANE 2134363466Sgshapiro unsigned long *ptlsa_flags; 2135363466Sgshapiro#endif 213638032Speter{ 213738032Speter register volatile int addrno = 0; 213890792Sgshapiro volatile int s; 213990792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 214038032Speter SOCKADDR addr; 214164562Sgshapiro SOCKADDR clt_addr; 214264562Sgshapiro int save_errno = 0; 214364562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 2144159609Sgshapiro volatile bool firstconnect = true; 214590792Sgshapiro SM_EVENT *volatile ev = NULL; 214690792Sgshapiro#if NETINET6 214790792Sgshapiro volatile bool v6found = false; 2148363466Sgshapiro#endif 214964562Sgshapiro volatile int family = InetMode; 215064562Sgshapiro SOCKADDR_LEN_T len; 215164562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 215264562Sgshapiro volatile bool clt_bind; 215364562Sgshapiro BITMAP256 d_flags; 215464562Sgshapiro char *p; 215564562Sgshapiro extern ENVELOPE BlankEnvelope; 2156363466Sgshapiro#if DANE 2157363466Sgshapiro unsigned long tlsa_flags; 2158363466Sgshapiro#endif 2159363466Sgshapiro#if DANE && NETINET6 2160363466Sgshapiro struct hostent *volatile hs = (struct hostent *) NULL; 2161363466Sgshapiro#else 2162363466Sgshapiro# define hs ((struct hostent *) NULL) 2163363466Sgshapiro#endif 216438032Speter 2165363466Sgshapiro#if DANE 2166363466Sgshapiro SM_REQUIRE(ptlsa_flags != NULL); 2167363466Sgshapiro tlsa_flags = *ptlsa_flags; 2168363466Sgshapiro *ptlsa_flags &= ~(TLSAFLALWAYS|TLSAFLSECURE); 2169363466Sgshapiro#endif 2170363466Sgshapiro 217190792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 217264562Sgshapiro clrbitmap(d_flags); 217390792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 217464562Sgshapiro { 217564562Sgshapiro for (; *p != '\0'; p++) 217664562Sgshapiro { 2177363466Sgshapiro if (!(SM_ISSPACE(*p))) 217871345Sgshapiro setbitn(bitidx(*p), d_flags); 217964562Sgshapiro } 218064562Sgshapiro } 218164562Sgshapiro 218290792Sgshapiro#if NETINET6 218364562Sgshapiro v4retry: 2184363466Sgshapiro#endif 218590792Sgshapiro clt_bind = false; 218664562Sgshapiro 218764562Sgshapiro /* Set up the address for outgoing connection. */ 218864562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 218990792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 219073188Sgshapiro *p != '\0') 219164562Sgshapiro { 219290792Sgshapiro#if NETINET6 219364562Sgshapiro char p6[INET6_ADDRSTRLEN]; 2194363466Sgshapiro#endif 219564562Sgshapiro 2196168515Sgshapiro memset(&clt_addr, '\0', sizeof(clt_addr)); 219764562Sgshapiro 219864562Sgshapiro /* infer the address family from the address itself */ 219964562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 220064562Sgshapiro switch (clt_addr.sa.sa_family) 220164562Sgshapiro { 220290792Sgshapiro#if NETINET 220364562Sgshapiro case AF_INET: 220473188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 220573188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 2206203004Sgshapiro clt_addr.sin.sin_addr.s_addr != 2207203004Sgshapiro htonl(INADDR_LOOPBACK)) 220864562Sgshapiro { 220990792Sgshapiro clt_bind = true; 2210168515Sgshapiro socksize = sizeof(struct sockaddr_in); 221164562Sgshapiro } 221264562Sgshapiro break; 221390792Sgshapiro#endif /* NETINET */ 221464562Sgshapiro 221590792Sgshapiro#if NETINET6 221664562Sgshapiro case AF_INET6: 221764562Sgshapiro if (inet_addr(p) != INADDR_NONE) 2218168515Sgshapiro (void) sm_snprintf(p6, sizeof(p6), 221990792Sgshapiro "IPv6:::ffff:%s", p); 222064562Sgshapiro else 2221168515Sgshapiro (void) sm_strlcpy(p6, p, sizeof(p6)); 222290792Sgshapiro if (anynet_pton(AF_INET6, p6, 222390792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 222473188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 222564562Sgshapiro { 222690792Sgshapiro clt_bind = true; 2227168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 222864562Sgshapiro } 222964562Sgshapiro break; 223090792Sgshapiro#endif /* NETINET6 */ 223164562Sgshapiro 223290792Sgshapiro#if 0 223364562Sgshapiro default: 223464562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 223564562Sgshapiro clt_addr.sa.sa_family); 223664562Sgshapiro break; 223790792Sgshapiro#endif /* 0 */ 223864562Sgshapiro } 223964562Sgshapiro if (clt_bind) 224064562Sgshapiro family = clt_addr.sa.sa_family; 224164562Sgshapiro } 224290792Sgshapiro 224390792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 224490792Sgshapiro if (!clt_bind) 224564562Sgshapiro { 224690792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 224764562Sgshapiro switch (clt_addr.sa.sa_family) 224864562Sgshapiro { 224990792Sgshapiro#if NETINET 225064562Sgshapiro case AF_INET: 225164562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 2252182352Sgshapiro clt_addr.sin.sin_addr.s_addr = LocalDaemon ? 2253182352Sgshapiro htonl(INADDR_LOOPBACK) : INADDR_ANY; 225464562Sgshapiro else 225590792Sgshapiro clt_bind = true; 225664562Sgshapiro if (clt_addr.sin.sin_port != 0) 225790792Sgshapiro clt_bind = true; 2258168515Sgshapiro socksize = sizeof(struct sockaddr_in); 225964562Sgshapiro break; 226090792Sgshapiro#endif /* NETINET */ 226190792Sgshapiro#if NETINET6 226264562Sgshapiro case AF_INET6: 226364562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 2264223067Sgshapiro clt_addr.sin6.sin6_addr = 2265223067Sgshapiro (LocalDaemon && V6LoopbackAddrFound) ? 2266182352Sgshapiro in6addr_loopback : in6addr_any; 226764562Sgshapiro else 226890792Sgshapiro clt_bind = true; 2269168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 227064562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 227190792Sgshapiro clt_bind = true; 227264562Sgshapiro break; 227390792Sgshapiro#endif /* NETINET6 */ 227490792Sgshapiro#if NETISO 227564562Sgshapiro case AF_ISO: 2276168515Sgshapiro socksize = sizeof(clt_addr.siso); 227790792Sgshapiro clt_bind = true; 227864562Sgshapiro break; 227990792Sgshapiro#endif /* NETISO */ 228064562Sgshapiro default: 228164562Sgshapiro break; 228264562Sgshapiro } 228364562Sgshapiro } 228464562Sgshapiro 228538032Speter /* 228638032Speter ** Set up the address for the mailer. 228738032Speter ** Accept "[a.b.c.d]" syntax for host name. 228838032Speter */ 228938032Speter 229073188Sgshapiro SM_SET_H_ERRNO(0); 229138032Speter errno = 0; 2292168515Sgshapiro memset(&CurHostAddr, '\0', sizeof(CurHostAddr)); 2293168515Sgshapiro memset(&addr, '\0', sizeof(addr)); 229438032Speter SmtpPhase = mci->mci_phase = "initial connection"; 229538032Speter CurHostName = host; 229638032Speter 229738032Speter if (host[0] == '[') 229838032Speter { 229964562Sgshapiro p = strchr(host, ']'); 230038032Speter if (p != NULL) 230138032Speter { 230290792Sgshapiro#if NETINET 230364562Sgshapiro unsigned long hid = INADDR_NONE; 2304363466Sgshapiro#endif 230590792Sgshapiro#if NETINET6 230664562Sgshapiro struct sockaddr_in6 hid6; 2307363466Sgshapiro#endif 230864562Sgshapiro 230938032Speter *p = '\0'; 231090792Sgshapiro#if NETINET6 2311168515Sgshapiro memset(&hid6, '\0', sizeof(hid6)); 2312363466Sgshapiro#endif 231390792Sgshapiro#if NETINET 231464562Sgshapiro if (family == AF_INET && 231564562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 231638032Speter { 231764562Sgshapiro addr.sin.sin_family = AF_INET; 231864562Sgshapiro addr.sin.sin_addr.s_addr = hid; 231964562Sgshapiro } 232064562Sgshapiro else 232190792Sgshapiro#endif /* NETINET */ 232290792Sgshapiro#if NETINET6 232364562Sgshapiro if (family == AF_INET6 && 232490792Sgshapiro anynet_pton(AF_INET6, &host[1], 232590792Sgshapiro &hid6.sin6_addr) == 1) 232664562Sgshapiro { 232764562Sgshapiro addr.sin6.sin6_family = AF_INET6; 232864562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 232964562Sgshapiro } 233064562Sgshapiro else 233190792Sgshapiro#endif /* NETINET6 */ 233264562Sgshapiro { 233338032Speter /* try it as a host name (avoid MX lookup) */ 233464562Sgshapiro hp = sm_gethostbyname(&host[1], family); 233538032Speter if (hp == NULL && p[-1] == '.') 233638032Speter { 233790792Sgshapiro#if NAMED_BIND 233838032Speter int oldopts = _res.options; 233938032Speter 234038032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 234190792Sgshapiro#endif /* NAMED_BIND */ 234238032Speter p[-1] = '\0'; 234364562Sgshapiro hp = sm_gethostbyname(&host[1], 234464562Sgshapiro family); 234538032Speter p[-1] = '.'; 234690792Sgshapiro#if NAMED_BIND 234738032Speter _res.options = oldopts; 2348363466Sgshapiro#endif 234938032Speter } 235038032Speter *p = ']'; 235138032Speter goto gothostent; 235238032Speter } 235338032Speter *p = ']'; 235438032Speter } 235538032Speter if (p == NULL) 235638032Speter { 235738032Speter extern char MsgBuf[]; 235838032Speter 235964562Sgshapiro usrerrenh("5.1.2", 236064562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 236164562Sgshapiro host); 236238032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 236364562Sgshapiro errno = EINVAL; 236438032Speter return EX_NOHOST; 236538032Speter } 236638032Speter } 236738032Speter else 236838032Speter { 236938032Speter /* contortion to get around SGI cc complaints */ 237038032Speter { 237164562Sgshapiro p = &host[strlen(host) - 1]; 2372363466Sgshapiro#if DANE 2373363466Sgshapiro if (tTd(16, 40)) 2374363466Sgshapiro sm_dprintf("makeconnection: tlsa_flags=%lX, host=%s\n", 2375363466Sgshapiro tlsa_flags, host); 2376363466Sgshapiro if (DANEMODE(tlsa_flags) == DANE_SECURE 2377363466Sgshapiro# if DNSSEC_TEST 2378363466Sgshapiro || tTd(8, 120) 2379363466Sgshapiro# endif 2380363466Sgshapiro ) 2381363466Sgshapiro { 2382363466Sgshapiro DNS_REPLY_T *rr; 2383363466Sgshapiro int err, herr; 2384363466Sgshapiro 2385363466Sgshapiro rr = dns_lookup_int(host, C_IN, FAM2T_(family), 2386363466Sgshapiro 0, 0, SM_RES_DNSSEC, 0, &err, &herr); 2387363466Sgshapiro 2388363466Sgshapiro /* 2389363466Sgshapiro ** Check for errors! 2390363466Sgshapiro ** If no ad: turn off TLSA. 2391363466Sgshapiro ** permail: use "normal" method? 2392363466Sgshapiro ** tempfail: delay or use "normal" method? 2393363466Sgshapiro */ 2394363466Sgshapiro 2395363466Sgshapiro if (rr != NULL && rr->dns_r_h.ad == 1) 2396363466Sgshapiro { 2397363466Sgshapiro *ptlsa_flags |= DANE_SECURE; 2398363466Sgshapiro if ((TLSAFLTEMP & *ptlsa_flags) != 0) 2399363466Sgshapiro { 2400363466Sgshapiro dns_free_data(rr); 2401363466Sgshapiro rr = NULL; 2402363466Sgshapiro return EX_TEMPFAIL; 2403363466Sgshapiro } 2404363466Sgshapiro hp = dns2he(rr, family); 2405363466Sgshapiro#if NETINET6 2406363466Sgshapiro hs = hp; 2407363466Sgshapiro#endif 2408363466Sgshapiro } 2409363466Sgshapiro 2410363466Sgshapiro /* other possible "tempfails"? */ 2411363466Sgshapiro if (rr == NULL && h_errno == TRY_AGAIN) 2412363466Sgshapiro goto gothostent; 2413363466Sgshapiro 2414363466Sgshapiro dns_free_data(rr); 2415363466Sgshapiro rr = NULL; 2416363466Sgshapiro } 2417363466Sgshapiro#endif 2418363466Sgshapiro if (hp == NULL) 2419363466Sgshapiro hp = sm_gethostbyname(host, family); 242038032Speter if (hp == NULL && *p == '.') 242138032Speter { 242290792Sgshapiro#if NAMED_BIND 242338032Speter int oldopts = _res.options; 242438032Speter 242538032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 2426363466Sgshapiro#endif 242738032Speter *p = '\0'; 242864562Sgshapiro hp = sm_gethostbyname(host, family); 242938032Speter *p = '.'; 243090792Sgshapiro#if NAMED_BIND 243138032Speter _res.options = oldopts; 2432363466Sgshapiro#endif 243338032Speter } 243438032Speter } 243538032Spetergothostent: 2436203004Sgshapiro if (hp == NULL || hp->h_addr == NULL) 243738032Speter { 243890792Sgshapiro#if NAMED_BIND 243938032Speter /* check for name server timeouts */ 244090792Sgshapiro# if NETINET6 244190792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 2442261194Sgshapiro (h_errno == TRY_AGAIN || errno == ETIMEDOUT)) 244338032Speter { 244490792Sgshapiro /* 244590792Sgshapiro ** An attempt with family AF_INET may 2446261194Sgshapiro ** succeed. By skipping the next section 244790792Sgshapiro ** of code, we will try AF_INET before 244890792Sgshapiro ** failing. 244990792Sgshapiro */ 245090792Sgshapiro 245190792Sgshapiro if (tTd(16, 10)) 245290792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 245338032Speter } 245490792Sgshapiro else 245590792Sgshapiro# endif /* NETINET6 */ 245690792Sgshapiro { 245790792Sgshapiro if (errno == ETIMEDOUT || 2458168515Sgshapiro# if _FFR_GETHBN_ExFILE 2459168515Sgshapiro# ifdef EMFILE 2460168515Sgshapiro errno == EMFILE || 2461363466Sgshapiro# endif 2462168515Sgshapiro# ifdef ENFILE 2463168515Sgshapiro errno == ENFILE || 2464363466Sgshapiro# endif 2465168515Sgshapiro# endif /* _FFR_GETHBN_ExFILE */ 246690792Sgshapiro h_errno == TRY_AGAIN || 246790792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 246890792Sgshapiro { 246990792Sgshapiro save_errno = errno; 247090792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 247190792Sgshapiro "4.4.3", NULL); 247290792Sgshapiro errno = save_errno; 247390792Sgshapiro return EX_TEMPFAIL; 247490792Sgshapiro } 247590792Sgshapiro } 247690792Sgshapiro#endif /* NAMED_BIND */ 247790792Sgshapiro#if NETINET6 247864562Sgshapiro /* 247964562Sgshapiro ** Try v6 first, then fall back to v4. 248064562Sgshapiro ** If we found a v6 address, but no v4 248164562Sgshapiro ** addresses, then TEMPFAIL. 248264562Sgshapiro */ 248364562Sgshapiro 248464562Sgshapiro if (family == AF_INET6) 248564562Sgshapiro { 248664562Sgshapiro family = AF_INET; 248764562Sgshapiro goto v4retry; 248864562Sgshapiro } 248964562Sgshapiro if (v6found) 249064562Sgshapiro goto v6tempfail; 249190792Sgshapiro#endif /* NETINET6 */ 249264562Sgshapiro save_errno = errno; 249338032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 249464562Sgshapiro errno = save_errno; 249564562Sgshapiro return EX_NOHOST; 249638032Speter } 249738032Speter addr.sa.sa_family = hp->h_addrtype; 249838032Speter switch (hp->h_addrtype) 249938032Speter { 250090792Sgshapiro#if NETINET 250138032Speter case AF_INET: 250264562Sgshapiro memmove(&addr.sin.sin_addr, 250364562Sgshapiro hp->h_addr, 250438032Speter INADDRSZ); 250538032Speter break; 250690792Sgshapiro#endif /* NETINET */ 250738032Speter 250890792Sgshapiro#if NETINET6 250964562Sgshapiro case AF_INET6: 251064562Sgshapiro memmove(&addr.sin6.sin6_addr, 251164562Sgshapiro hp->h_addr, 251264562Sgshapiro IN6ADDRSZ); 251364562Sgshapiro break; 251490792Sgshapiro#endif /* NETINET6 */ 251564562Sgshapiro 251638032Speter default: 2517168515Sgshapiro if (hp->h_length > sizeof(addr.sa.sa_data)) 251838032Speter { 251938032Speter syserr("makeconnection: long sa_data: family %d len %d", 252038032Speter hp->h_addrtype, hp->h_length); 252138032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 252264562Sgshapiro errno = EINVAL; 252338032Speter return EX_NOHOST; 252438032Speter } 252590792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 252638032Speter break; 252738032Speter } 252838032Speter addrno = 1; 252938032Speter } 253038032Speter 2531363466Sgshapiro#if _FFR_TESTS 2532363466Sgshapiro /* 2533363466Sgshapiro ** Hack for testing. 2534363466Sgshapiro ** Hardcoded: 2535363466Sgshapiro ** 10.1.1.12: see meta1.tns XREF IP address 2536363466Sgshapiro ** 8754: see common.sh XREF SNKPORT2 2537363466Sgshapiro */ 2538363466Sgshapiro 2539363466Sgshapiro if (tTd(77, 101) && hp->h_addrtype == AF_INET && 2540363466Sgshapiro addr.sin.sin_addr.s_addr == inet_addr("10.1.1.12")) 2541363466Sgshapiro { 2542363466Sgshapiro addr.sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 2543363466Sgshapiro port = htons(8754); 2544363466Sgshapiro sm_dprintf("hack host=%s addr=[%s].%d\n", host, 2545363466Sgshapiro anynet_ntoa(&addr), ntohs(port)); 2546363466Sgshapiro } 2547363466Sgshapiro#endif 2548363466Sgshapiro 254938032Speter /* 255038032Speter ** Determine the port number. 255138032Speter */ 255238032Speter 255338032Speter if (port == 0) 255438032Speter { 255590792Sgshapiro#ifdef NO_GETSERVBYNAME 255664562Sgshapiro port = htons(25); 255790792Sgshapiro#else /* NO_GETSERVBYNAME */ 255838032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 255938032Speter 256038032Speter if (sp == NULL) 256138032Speter { 256238032Speter if (LogLevel > 2) 256338032Speter sm_syslog(LOG_ERR, NOQID, 256464562Sgshapiro "makeconnection: service \"smtp\" unknown"); 256538032Speter port = htons(25); 256638032Speter } 256738032Speter else 256838032Speter port = sp->s_port; 256990792Sgshapiro#endif /* NO_GETSERVBYNAME */ 257038032Speter } 257138032Speter 257290792Sgshapiro#if NETINET6 257390792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 257490792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 257590792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 257690792Sgshapiro { 257790792Sgshapiro /* 257890792Sgshapiro ** Ignore mapped IPv4 address since 257990792Sgshapiro ** there is a ClientPortOptions setting 258090792Sgshapiro ** for IPv4. 258190792Sgshapiro */ 258290792Sgshapiro 258390792Sgshapiro goto nextaddr; 258490792Sgshapiro } 258590792Sgshapiro#endif /* NETINET6 */ 258690792Sgshapiro 258738032Speter switch (addr.sa.sa_family) 258838032Speter { 258990792Sgshapiro#if NETINET 259038032Speter case AF_INET: 259138032Speter addr.sin.sin_port = port; 2592168515Sgshapiro addrlen = sizeof(struct sockaddr_in); 259338032Speter break; 259490792Sgshapiro#endif /* NETINET */ 259538032Speter 259690792Sgshapiro#if NETINET6 259764562Sgshapiro case AF_INET6: 259864562Sgshapiro addr.sin6.sin6_port = port; 2599168515Sgshapiro addrlen = sizeof(struct sockaddr_in6); 260064562Sgshapiro break; 260190792Sgshapiro#endif /* NETINET6 */ 260264562Sgshapiro 260390792Sgshapiro#if NETISO 260438032Speter case AF_ISO: 260538032Speter /* assume two byte transport selector */ 260664562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 2607168515Sgshapiro addrlen = sizeof(struct sockaddr_iso); 260838032Speter break; 260990792Sgshapiro#endif /* NETISO */ 261038032Speter 261138032Speter default: 261238032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 261338032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 261464562Sgshapiro errno = EINVAL; 2615363466Sgshapiro FREEHOSTENT(hp, hs); 261664562Sgshapiro return EX_NOHOST; 261738032Speter } 261838032Speter 261938032Speter /* 262038032Speter ** Try to actually open the connection. 262138032Speter */ 262238032Speter 262390792Sgshapiro#if XLA 262438032Speter /* if too many connections, don't bother trying */ 262538032Speter if (!xla_noqueue_ok(host)) 262671345Sgshapiro { 2627363466Sgshapiro FREEHOSTENT(hp, hs); 262838032Speter return EX_TEMPFAIL; 262971345Sgshapiro } 263090792Sgshapiro#endif /* XLA */ 263138032Speter 2632363466Sgshapiro#if _FFR_OCC 2633363466Sgshapiro# define OCC_CLOSE occ_close(e, mci, host, &addr) 2634363466Sgshapiro /* HACK!!!! just to see if this can work at all... */ 2635363466Sgshapiro if (occ_exceeded(e, mci, host, &addr)) 2636363466Sgshapiro { 2637363466Sgshapiro FREEHOSTENT(hp, hs); 2638363466Sgshapiro sm_syslog(LOG_DEBUG, e->e_id, 2639363466Sgshapiro "stat=occ_exceeded, host=%s, addr=%s", 2640363466Sgshapiro host, anynet_ntoa(&addr)); 2641363466Sgshapiro 2642363466Sgshapiro /* 2643363466Sgshapiro ** to get a more specific stat= message set errno 2644363466Sgshapiro ** or make up one in sm, see sm_errstring() 2645363466Sgshapiro */ 2646363466Sgshapiro 2647363466Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", "450 occ_exceeded"); /* check D.S.N */ 2648363466Sgshapiro errno = EAGAIN; 2649363466Sgshapiro return EX_TEMPFAIL; 2650363466Sgshapiro } 2651363466Sgshapiro#else /* _FFR_OCC */ 2652363466Sgshapiro# define OCC_CLOSE 2653363466Sgshapiro#endif /* _FFR_OCC */ 2654363466Sgshapiro 265538032Speter for (;;) 265638032Speter { 265738032Speter if (tTd(16, 1)) 265890792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 265990792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 266090792Sgshapiro (int) addr.sa.sa_family); 266138032Speter 266238032Speter /* save for logging */ 266338032Speter CurHostAddr = addr; 266438032Speter 266590792Sgshapiro#if HASRRESVPORT 266638032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 266738032Speter { 266838032Speter int rport = IPPORT_RESERVED - 1; 266938032Speter 267038032Speter s = rresvport(&rport); 267138032Speter } 267238032Speter else 267390792Sgshapiro#endif /* HASRRESVPORT */ 267438032Speter { 267590792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 267638032Speter } 267738032Speter if (s < 0) 267838032Speter { 267964562Sgshapiro save_errno = errno; 268038032Speter syserr("makeconnection: cannot create socket"); 268190792Sgshapiro#if XLA 268238032Speter xla_host_end(host); 2683363466Sgshapiro#endif 268438032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 2685363466Sgshapiro FREEHOSTENT(hp, hs); 268664562Sgshapiro errno = save_errno; 2687363466Sgshapiro OCC_CLOSE; 268838032Speter return EX_TEMPFAIL; 268938032Speter } 269038032Speter 269190792Sgshapiro#ifdef SO_SNDBUF 269290792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 269338032Speter { 269438032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 269590792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 269690792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 269738032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 269838032Speter } 269990792Sgshapiro#endif /* SO_SNDBUF */ 270090792Sgshapiro#ifdef SO_RCVBUF 270190792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 270264562Sgshapiro { 270364562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 270490792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 270590792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 270664562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 270764562Sgshapiro } 270890792Sgshapiro#endif /* SO_RCVBUF */ 270938032Speter 271038032Speter if (tTd(16, 1)) 271190792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 271238032Speter 271338032Speter /* turn on network debugging? */ 271438032Speter if (tTd(16, 101)) 271538032Speter { 271638032Speter int on = 1; 271764562Sgshapiro 271838032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 2719168515Sgshapiro (char *)&on, sizeof(on)); 272038032Speter } 272190792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 272290792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 272390792Sgshapiro errno = 0; /* for debugging */ 272438032Speter 272564562Sgshapiro if (clt_bind) 272664562Sgshapiro { 272764562Sgshapiro int on = 1; 272864562Sgshapiro 272964562Sgshapiro switch (clt_addr.sa.sa_family) 273064562Sgshapiro { 273190792Sgshapiro#if NETINET 273264562Sgshapiro case AF_INET: 273364562Sgshapiro if (clt_addr.sin.sin_port != 0) 273464562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 273564562Sgshapiro SO_REUSEADDR, 273664562Sgshapiro (char *) &on, 2737168515Sgshapiro sizeof(on)); 273864562Sgshapiro break; 273990792Sgshapiro#endif /* NETINET */ 274064562Sgshapiro 274190792Sgshapiro#if NETINET6 274264562Sgshapiro case AF_INET6: 274364562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 274464562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 274564562Sgshapiro SO_REUSEADDR, 274664562Sgshapiro (char *) &on, 2747168515Sgshapiro sizeof(on)); 274864562Sgshapiro break; 274990792Sgshapiro#endif /* NETINET6 */ 275064562Sgshapiro } 275164562Sgshapiro 275264562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 275364562Sgshapiro { 275464562Sgshapiro save_errno = errno; 275564562Sgshapiro (void) close(s); 275664562Sgshapiro errno = save_errno; 275764562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 275864562Sgshapiro anynet_ntoa(&clt_addr)); 2759363466Sgshapiro FREEHOSTENT(hp, hs); 276064562Sgshapiro errno = save_errno; 2761363466Sgshapiro OCC_CLOSE; 276264562Sgshapiro return EX_TEMPFAIL; 276364562Sgshapiro } 276464562Sgshapiro } 276564562Sgshapiro 276638032Speter /* 276738032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 276838032Speter ** Time out the connect to avoid this problem. 276938032Speter */ 277038032Speter 277138032Speter if (setjmp(CtxConnectTimeout) == 0) 277238032Speter { 277338032Speter int i; 277438032Speter 277538032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 277690792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 277790792Sgshapiro connecttimeout, 0); 277838032Speter else if (TimeOuts.to_connect != 0) 277990792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 278090792Sgshapiro connecttimeout, 0); 278138032Speter else 278238032Speter ev = NULL; 278338032Speter 278464562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 278564562Sgshapiro { 278690792Sgshapiro#if NETINET 278764562Sgshapiro case AF_INET: 278864562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 2789223067Sgshapiro addr.sa.sa_family = ConnectOnlyTo.sa.sa_family; 2790363466Sgshapiro if (ConnectOnlyTo.sin.sin_port != 0) 2791363466Sgshapiro { 2792363466Sgshapiro port = ConnectOnlyTo.sin.sin_port; 2793363466Sgshapiro addr.sin.sin_port = port; 2794363466Sgshapiro } 279564562Sgshapiro break; 279690792Sgshapiro#endif /* NETINET */ 279764562Sgshapiro 279890792Sgshapiro#if NETINET6 279964562Sgshapiro case AF_INET6: 280064562Sgshapiro memmove(&addr.sin6.sin6_addr, 280164562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 280264562Sgshapiro IN6ADDRSZ); 2803363466Sgshapiro if (ConnectOnlyTo.sin6.sin6_port != 0) 2804363466Sgshapiro { 2805363466Sgshapiro port = ConnectOnlyTo.sin6.sin6_port; 2806363466Sgshapiro addr.sin6.sin6_port = port; 2807363466Sgshapiro } 280864562Sgshapiro break; 280990792Sgshapiro#endif /* NETINET6 */ 281064562Sgshapiro } 2811141858Sgshapiro if (tTd(16, 1)) 2812363466Sgshapiro sm_dprintf("Connecting to [%s].%d...\n", 2813363466Sgshapiro anynet_ntoa(&addr), ntohs(port)); 2814363466Sgshapiro 281538032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 281664562Sgshapiro save_errno = errno; 281738032Speter if (ev != NULL) 281890792Sgshapiro sm_clrevent(ev); 281938032Speter if (i >= 0) 282038032Speter break; 282138032Speter } 282238032Speter else 282364562Sgshapiro save_errno = errno; 282438032Speter 282594334Sgshapiro /* couldn't connect.... figure out why */ 282694334Sgshapiro (void) close(s); 282794334Sgshapiro 282838032Speter /* if running demand-dialed connection, try again */ 282990792Sgshapiro if (DialDelay > 0 && firstconnect && 283090792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 283138032Speter { 283238032Speter if (tTd(16, 1)) 283390792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 283490792Sgshapiro sm_errstring(save_errno)); 283590792Sgshapiro firstconnect = false; 283664562Sgshapiro (void) sleep(DialDelay); 283738032Speter continue; 283838032Speter } 283938032Speter 284090792Sgshapiro if (LogLevel > 13) 284138032Speter sm_syslog(LOG_INFO, e->e_id, 2842363466Sgshapiro "makeconnection (%s [%s].%d (%d)) failed: %s", 2843363466Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 2844363466Sgshapiro (int) addr.sa.sa_family, 284590792Sgshapiro sm_errstring(save_errno)); 284638032Speter 284790792Sgshapiro#if NETINET6 284890792Sgshapironextaddr: 284990792Sgshapiro#endif /* NETINET6 */ 285090792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 285190792Sgshapiro (enough == 0 || curtime() < enough)) 285238032Speter { 285338032Speter if (tTd(16, 1)) 285490792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 285590792Sgshapiro sm_errstring(save_errno)); 285638032Speter switch (addr.sa.sa_family) 285738032Speter { 285890792Sgshapiro#if NETINET 285938032Speter case AF_INET: 286064562Sgshapiro memmove(&addr.sin.sin_addr, 286164562Sgshapiro hp->h_addr_list[addrno++], 286264562Sgshapiro INADDRSZ); 286338032Speter break; 286490792Sgshapiro#endif /* NETINET */ 286538032Speter 286690792Sgshapiro#if NETINET6 286764562Sgshapiro case AF_INET6: 286864562Sgshapiro memmove(&addr.sin6.sin6_addr, 286964562Sgshapiro hp->h_addr_list[addrno++], 287064562Sgshapiro IN6ADDRSZ); 287164562Sgshapiro break; 287290792Sgshapiro#endif /* NETINET6 */ 287364562Sgshapiro 287438032Speter default: 287564562Sgshapiro memmove(addr.sa.sa_data, 287664562Sgshapiro hp->h_addr_list[addrno++], 287738032Speter hp->h_length); 287838032Speter break; 287938032Speter } 288038032Speter continue; 288138032Speter } 288264562Sgshapiro errno = save_errno; 288338032Speter 288490792Sgshapiro#if NETINET6 288564562Sgshapiro if (family == AF_INET6) 288664562Sgshapiro { 288764562Sgshapiro if (tTd(16, 1)) 288890792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 288990792Sgshapiro sm_errstring(save_errno)); 289090792Sgshapiro v6found = true; 289164562Sgshapiro family = AF_INET; 2892363466Sgshapiro FREEHOSTENT(hp, hs); 289364562Sgshapiro goto v4retry; 289464562Sgshapiro } 289564562Sgshapiro v6tempfail: 289690792Sgshapiro#endif /* NETINET6 */ 289738032Speter /* couldn't open connection */ 289890792Sgshapiro#if NETINET6 289964562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 290064562Sgshapiro if (errno > 0) 2901363466Sgshapiro#endif 290264562Sgshapiro save_errno = errno; 290364562Sgshapiro if (tTd(16, 1)) 290490792Sgshapiro sm_dprintf("Connect failed (%s)\n", 290590792Sgshapiro sm_errstring(save_errno)); 290690792Sgshapiro#if XLA 290738032Speter xla_host_end(host); 2908363466Sgshapiro#endif 290938032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 2910363466Sgshapiro FREEHOSTENT(hp, hs); 291164562Sgshapiro errno = save_errno; 2912363466Sgshapiro OCC_CLOSE; 291338032Speter return EX_TEMPFAIL; 291438032Speter } 291538032Speter 2916363466Sgshapiro FREEHOSTENT(hp, hs); 291771345Sgshapiro 291838032Speter /* connection ok, put it into canonical form */ 291964562Sgshapiro mci->mci_out = NULL; 292090792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 292190792Sgshapiro (void *) &s, 2922132943Sgshapiro SM_IO_WRONLY_B, NULL)) == NULL || 292338032Speter (s = dup(s)) < 0 || 292490792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 292590792Sgshapiro (void *) &s, 2926132943Sgshapiro SM_IO_RDONLY_B, NULL)) == NULL) 292738032Speter { 292864562Sgshapiro save_errno = errno; 292938032Speter syserr("cannot open SMTP client channel, fd=%d", s); 293038032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 293164562Sgshapiro if (mci->mci_out != NULL) 293290792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 293364562Sgshapiro (void) close(s); 293464562Sgshapiro errno = save_errno; 2935363466Sgshapiro OCC_CLOSE; 293638032Speter return EX_TEMPFAIL; 293738032Speter } 293890792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 293938032Speter 294090792Sgshapiro /* set {client_flags} */ 294190792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 294290792Sgshapiro { 294390792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 294490792Sgshapiro macid("{client_flags}"), 294590792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 294690792Sgshapiro } 294790792Sgshapiro else 294890792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 294990792Sgshapiro macid("{client_flags}"), ""); 295090792Sgshapiro 295190792Sgshapiro /* "add" {client_flags} to bitmap */ 295290792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 295390792Sgshapiro { 295490792Sgshapiro /* look for just this one flag */ 295590792Sgshapiro setbitn(D_IFNHELO, d_flags); 295690792Sgshapiro } 295790792Sgshapiro 295864562Sgshapiro /* find out name for Interface through which we connect */ 2959168515Sgshapiro len = sizeof(addr); 296064562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 296164562Sgshapiro { 296264562Sgshapiro char *name; 296364562Sgshapiro 2964363466Sgshapiro if (!isloopback(addr)) 2965363466Sgshapiro { 2966363466Sgshapiro char familystr[5]; 296764562Sgshapiro 2968363466Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 2969363466Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 2970363466Sgshapiro (void) sm_snprintf(familystr, sizeof(familystr), "%d", 2971363466Sgshapiro addr.sa.sa_family); 2972363466Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 2973363466Sgshapiro macid("{if_family_out}"), familystr); 2974363466Sgshapiro } 2975363466Sgshapiro else 2976363466Sgshapiro { 2977363466Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 2978363466Sgshapiro macid("{if_addr_out}"), NULL); 2979363466Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 2980363466Sgshapiro macid("{if_family_out}"), NULL); 2981363466Sgshapiro } 2982363466Sgshapiro 298364562Sgshapiro name = hostnamebyanyaddr(&addr); 298490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 298590792Sgshapiro macid("{if_name_out}"), name); 298664562Sgshapiro if (LogLevel > 11) 298764562Sgshapiro { 298864562Sgshapiro /* log connection information */ 298964562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 299064562Sgshapiro "SMTP outgoing connect on %.40s", name); 299164562Sgshapiro } 299264562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 299364562Sgshapiro { 299464562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 299564562Sgshapiro mci->mci_heloname = newstr(name); 299664562Sgshapiro } 299764562Sgshapiro } 299864562Sgshapiro else 299964562Sgshapiro { 300090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 300190792Sgshapiro macid("{if_name_out}"), NULL); 300290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 300390792Sgshapiro macid("{if_addr_out}"), NULL); 300490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 300590792Sgshapiro macid("{if_family_out}"), NULL); 300664562Sgshapiro } 3007132943Sgshapiro 3008132943Sgshapiro /* Use the configured HeloName as appropriate */ 3009132943Sgshapiro if (HeloName != NULL && HeloName[0] != '\0') 3010223067Sgshapiro { 3011363466Sgshapiro SM_FREE(mci->mci_heloname); 3012132943Sgshapiro mci->mci_heloname = newstr(HeloName); 3013223067Sgshapiro } 3014132943Sgshapiro 301538032Speter mci_setstat(mci, EX_OK, NULL, NULL); 301664562Sgshapiro return EX_OK; 301738032Speter} 301864562Sgshapiro 301964562Sgshapirostatic void 3020141858Sgshapiroconnecttimeout(ignore) 3021141858Sgshapiro int ignore; 302264562Sgshapiro{ 302377349Sgshapiro /* 302477349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 302577349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 302677349Sgshapiro ** DOING. 302777349Sgshapiro */ 302877349Sgshapiro 302964562Sgshapiro errno = ETIMEDOUT; 303064562Sgshapiro longjmp(CtxConnectTimeout, 1); 303164562Sgshapiro} 303290792Sgshapiro/* 303364562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 303464562Sgshapiro** 303564562Sgshapiro** Parameters: 303664562Sgshapiro** mux_path -- the path of the socket to connect to. 303764562Sgshapiro** mci -- a pointer to the mail connection information 303864562Sgshapiro** structure to be filled in. 303964562Sgshapiro** 304064562Sgshapiro** Returns: 304164562Sgshapiro** An exit code telling whether the connection could be 304264562Sgshapiro** made and if not why not. 304364562Sgshapiro** 304464562Sgshapiro** Side Effects: 304564562Sgshapiro** none. 304664562Sgshapiro*/ 304764562Sgshapiro 304890792Sgshapiro#if NETUNIX 304990792Sgshapiroint 305090792Sgshapiromakeconnection_ds(mux_path, mci) 305164562Sgshapiro char *mux_path; 305264562Sgshapiro register MCI *mci; 305364562Sgshapiro{ 305464562Sgshapiro int sock; 305564562Sgshapiro int rval, save_errno; 305664562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 305764562Sgshapiro struct sockaddr_un unix_addr; 305864562Sgshapiro 305964562Sgshapiro /* if not safe, don't connect */ 306064562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 306164562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 306264562Sgshapiro 306364562Sgshapiro if (rval != 0) 306464562Sgshapiro { 3065132943Sgshapiro syserr("makeconnection_ds: unsafe domain socket %s", 3066132943Sgshapiro mux_path); 306764562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 306864562Sgshapiro errno = rval; 306964562Sgshapiro return EX_TEMPFAIL; 307064562Sgshapiro } 307164562Sgshapiro 307264562Sgshapiro /* prepare address structure */ 3073168515Sgshapiro memset(&unix_addr, '\0', sizeof(unix_addr)); 307464562Sgshapiro unix_addr.sun_family = AF_UNIX; 307564562Sgshapiro 3076168515Sgshapiro if (strlen(mux_path) >= sizeof(unix_addr.sun_path)) 307764562Sgshapiro { 3078132943Sgshapiro syserr("makeconnection_ds: domain socket name %s too long", 3079132943Sgshapiro mux_path); 308090792Sgshapiro 308190792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 308264562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 308364562Sgshapiro errno = ENAMETOOLONG; 308464562Sgshapiro return EX_UNAVAILABLE; 308564562Sgshapiro } 308690792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 3087168515Sgshapiro sizeof(unix_addr.sun_path)); 308864562Sgshapiro 308964562Sgshapiro /* initialize domain socket */ 309064562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 309164562Sgshapiro if (sock == -1) 309264562Sgshapiro { 309364562Sgshapiro save_errno = errno; 3094132943Sgshapiro syserr("makeconnection_ds: could not create domain socket %s", 3095132943Sgshapiro mux_path); 309664562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 309764562Sgshapiro errno = save_errno; 309864562Sgshapiro return EX_TEMPFAIL; 309964562Sgshapiro } 310064562Sgshapiro 310164562Sgshapiro /* connect to server */ 310264562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 310364562Sgshapiro sizeof(unix_addr)) == -1) 310464562Sgshapiro { 310564562Sgshapiro save_errno = errno; 310664562Sgshapiro syserr("Could not connect to socket %s", mux_path); 310764562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 310864562Sgshapiro (void) close(sock); 310964562Sgshapiro errno = save_errno; 311064562Sgshapiro return EX_TEMPFAIL; 311164562Sgshapiro } 311264562Sgshapiro 311364562Sgshapiro /* connection ok, put it into canonical form */ 311464562Sgshapiro mci->mci_out = NULL; 311590792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 3116132943Sgshapiro (void *) &sock, SM_IO_WRONLY_B, NULL)) 311790792Sgshapiro == NULL 311890792Sgshapiro || (sock = dup(sock)) < 0 || 311990792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 3120132943Sgshapiro (void *) &sock, SM_IO_RDONLY_B, NULL)) 312190792Sgshapiro == NULL) 312264562Sgshapiro { 312364562Sgshapiro save_errno = errno; 312464562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 312564562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 312664562Sgshapiro if (mci->mci_out != NULL) 312790792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 312864562Sgshapiro (void) close(sock); 312964562Sgshapiro errno = save_errno; 313064562Sgshapiro return EX_TEMPFAIL; 313164562Sgshapiro } 313290792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 313364562Sgshapiro 313464562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 313564562Sgshapiro errno = 0; 313664562Sgshapiro return EX_OK; 313764562Sgshapiro} 313890792Sgshapiro#endif /* NETUNIX */ 313990792Sgshapiro/* 314090792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 314177349Sgshapiro** 314277349Sgshapiro** Parameters: 314390792Sgshapiro** none. 314477349Sgshapiro** 314577349Sgshapiro** Returns: 314677349Sgshapiro** none. 314777349Sgshapiro** 314877349Sgshapiro** Side Effects: 314990792Sgshapiro** closes control socket, exits. 315077349Sgshapiro*/ 315177349Sgshapiro 315290792Sgshapirovoid 315390792Sgshapiroshutdown_daemon() 315477349Sgshapiro{ 315590792Sgshapiro int i; 315690792Sgshapiro char *reason; 315777349Sgshapiro 315890792Sgshapiro sm_allsignals(true); 315990792Sgshapiro 316090792Sgshapiro reason = ShutdownRequest; 316190792Sgshapiro ShutdownRequest = NULL; 316290792Sgshapiro PendingSignal = 0; 316390792Sgshapiro 3164132943Sgshapiro if (LogLevel > 9) 3165132943Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s", 316690792Sgshapiro reason == NULL ? "implicit call" : reason); 316790792Sgshapiro 316890792Sgshapiro FileName = NULL; 316990792Sgshapiro closecontrolsocket(true); 317090792Sgshapiro#if XLA 317190792Sgshapiro xla_all_end(); 3172363466Sgshapiro#endif 317390792Sgshapiro 317490792Sgshapiro for (i = 0; i < NDaemons; i++) 317590792Sgshapiro { 317690792Sgshapiro if (Daemons[i].d_socket >= 0) 317790792Sgshapiro { 317890792Sgshapiro (void) close(Daemons[i].d_socket); 317990792Sgshapiro Daemons[i].d_socket = -1; 318090792Sgshapiro 3181285229Sgshapiro#if NETUNIX 318290792Sgshapiro /* Remove named sockets */ 318390792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 318490792Sgshapiro { 318590792Sgshapiro int rval; 318690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 318790792Sgshapiro 318890792Sgshapiro /* if not safe, don't use it */ 318990792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 319090792Sgshapiro RunAsUid, RunAsGid, 319190792Sgshapiro RunAsUserName, sff, 319290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 319390792Sgshapiro if (rval == 0 && 319490792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 319590792Sgshapiro { 319690792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 319790792Sgshapiro "Could not remove daemon %s socket: %s: %s", 319890792Sgshapiro Daemons[i].d_name, 319990792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 320090792Sgshapiro sm_errstring(errno)); 320190792Sgshapiro } 320290792Sgshapiro } 3203285229Sgshapiro#endif /* NETUNIX */ 320490792Sgshapiro } 320590792Sgshapiro } 320690792Sgshapiro 320790792Sgshapiro finis(false, true, EX_OK); 320877349Sgshapiro} 320990792Sgshapiro/* 321077349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 321177349Sgshapiro** 321277349Sgshapiro** Parameters: 321377349Sgshapiro** none. 321477349Sgshapiro** 321577349Sgshapiro** Returns: 321677349Sgshapiro** none. 321777349Sgshapiro** 321877349Sgshapiro** Side Effects: 321977349Sgshapiro** restarts the daemon or exits if restart fails. 322077349Sgshapiro*/ 322177349Sgshapiro 322280785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 322380785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 322480785Sgshapirodo \ 322580785Sgshapiro{ \ 322690792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 322780785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 322890792Sgshapiro (void) sm_signal((sig), (old)); \ 322980785Sgshapiro} while (0) 323080785Sgshapiro 323190792Sgshapirovoid 323277349Sgshapirorestart_daemon() 323377349Sgshapiro{ 323490792Sgshapiro bool drop; 323577349Sgshapiro int save_errno; 323677349Sgshapiro char *reason; 323780785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 323877349Sgshapiro extern int DtableSize; 323977349Sgshapiro 324080785Sgshapiro /* clear the events to turn off SIGALRMs */ 324190792Sgshapiro sm_clear_events(); 324290792Sgshapiro sm_allsignals(true); 324377349Sgshapiro 324477349Sgshapiro reason = RestartRequest; 324577349Sgshapiro RestartRequest = NULL; 324677349Sgshapiro PendingSignal = 0; 324777349Sgshapiro 324877349Sgshapiro if (SaveArgv[0][0] != '/') 324977349Sgshapiro { 325077349Sgshapiro if (LogLevel > 3) 325177349Sgshapiro sm_syslog(LOG_INFO, NOQID, 325277349Sgshapiro "could not restart: need full path"); 325390792Sgshapiro finis(false, true, EX_OSFILE); 325490792Sgshapiro /* NOTREACHED */ 325577349Sgshapiro } 325677349Sgshapiro if (LogLevel > 3) 325777349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 325877349Sgshapiro SaveArgv[0], 325977349Sgshapiro reason == NULL ? "implicit call" : reason); 326077349Sgshapiro 326190792Sgshapiro closecontrolsocket(true); 326298121Sgshapiro#if SM_CONF_SHM 326398121Sgshapiro cleanup_shm(DaemonPid == getpid()); 3264363466Sgshapiro#endif 326590792Sgshapiro 3266132943Sgshapiro /* close locked pid file */ 3267132943Sgshapiro close_sendmail_pid(); 3268132943Sgshapiro 326990792Sgshapiro /* 327090792Sgshapiro ** Want to drop to the user who started the process in all cases 327190792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 327290792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 327390792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 327490792Sgshapiro */ 327590792Sgshapiro 327690792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 327790792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 327890792Sgshapiro 327990792Sgshapiro if (drop_privileges(drop) != EX_OK) 328077349Sgshapiro { 328177349Sgshapiro if (LogLevel > 0) 328277349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 328390792Sgshapiro "could not drop privileges: %s", 328490792Sgshapiro sm_errstring(errno)); 328590792Sgshapiro finis(false, true, EX_OSERR); 328690792Sgshapiro /* NOTREACHED */ 328777349Sgshapiro } 328877349Sgshapiro 3289132943Sgshapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 329077349Sgshapiro 329180785Sgshapiro /* 329280785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 329380785Sgshapiro ** However, the default action can be "terminate", so it isn't 329480785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 329580785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 329680785Sgshapiro */ 329780785Sgshapiro 329880785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 329980785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 330080785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 330180785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 330280785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 330380785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 330480785Sgshapiro#ifdef SIGUSR1 330580785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 3306363466Sgshapiro#endif 330794334Sgshapiro 330894334Sgshapiro /* Turn back on signals */ 330990792Sgshapiro sm_allsignals(false); 331077349Sgshapiro 331177349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 331277349Sgshapiro save_errno = errno; 331377349Sgshapiro 331480785Sgshapiro /* block signals again and restore needed signals */ 331590792Sgshapiro sm_allsignals(true); 331680785Sgshapiro 331780785Sgshapiro /* For finis() events */ 331890792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 331980785Sgshapiro 332080785Sgshapiro#ifdef SIGUSR1 332180785Sgshapiro /* For debugging finis() */ 332290792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 3323363466Sgshapiro#endif 332477349Sgshapiro 332577349Sgshapiro errno = save_errno; 332677349Sgshapiro if (LogLevel > 0) 332790792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 332890792Sgshapiro SaveArgv[0], sm_errstring(errno)); 332990792Sgshapiro finis(false, true, EX_OSFILE); 333090792Sgshapiro /* NOTREACHED */ 333177349Sgshapiro} 333290792Sgshapiro/* 333338032Speter** MYHOSTNAME -- return the name of this host. 333438032Speter** 333538032Speter** Parameters: 333638032Speter** hostbuf -- a place to return the name of this host. 333738032Speter** size -- the size of hostbuf. 333838032Speter** 333938032Speter** Returns: 334038032Speter** A list of aliases for this host. 334138032Speter** 334238032Speter** Side Effects: 334338032Speter** Adds numeric codes to $=w. 334438032Speter*/ 334538032Speter 334638032Speterstruct hostent * 334738032Spetermyhostname(hostbuf, size) 334838032Speter char hostbuf[]; 334938032Speter int size; 335038032Speter{ 335138032Speter register struct hostent *hp; 335238032Speter 335373188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 335490792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 335564562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 335690792Sgshapiro#if NETINET && NETINET6 335780785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 335880785Sgshapiro { 335980785Sgshapiro /* 336080785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 336180785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 336280785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 336380785Sgshapiro */ 336480785Sgshapiro 336580785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 336680785Sgshapiro } 336790792Sgshapiro#endif /* NETINET && NETINET6 */ 336838032Speter if (hp == NULL) 336938032Speter return NULL; 337038032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 337164562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 337264562Sgshapiro 337390792Sgshapiro#if NETINFO 337464562Sgshapiro if (strchr(hostbuf, '.') == NULL) 337538032Speter { 337664562Sgshapiro char *domainname; 337764562Sgshapiro 337864562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 337964562Sgshapiro "domain", '\0'); 338064562Sgshapiro if (domainname != NULL && 338164562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 338290792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 338338032Speter } 338490792Sgshapiro#endif /* NETINFO */ 338538032Speter 338638032Speter /* 338738032Speter ** If there is still no dot in the name, try looking for a 338838032Speter ** dotted alias. 338938032Speter */ 339038032Speter 339138032Speter if (strchr(hostbuf, '.') == NULL) 339238032Speter { 339338032Speter char **ha; 339438032Speter 339564562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 339638032Speter { 339738032Speter if (strchr(*ha, '.') != NULL) 339838032Speter { 339964562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 340038032Speter hostbuf[size - 1] = '\0'; 340138032Speter break; 340238032Speter } 340338032Speter } 340438032Speter } 340538032Speter 340638032Speter /* 340738032Speter ** If _still_ no dot, wait for a while and try again -- it is 340838032Speter ** possible that some service is starting up. This can result 340938032Speter ** in excessive delays if the system is badly configured, but 341038032Speter ** there really isn't a way around that, particularly given that 341138032Speter ** the config file hasn't been read at this point. 341238032Speter ** All in all, a bit of a mess. 341338032Speter */ 341438032Speter 341538032Speter if (strchr(hostbuf, '.') == NULL && 3416363466Sgshapiro getcanonname(hostbuf, size, true, NULL) == HOST_NOTFOUND) 341738032Speter { 3418182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_CRIT, NOQID, 341964562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 342064562Sgshapiro hostbuf); 342138032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 342238032Speter hostbuf); 342364562Sgshapiro (void) sleep(60); 3424363466Sgshapiro if (getcanonname(hostbuf, size, true, NULL) == HOST_NOTFOUND) 342538032Speter { 3426182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_ALERT, NOQID, 342764562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 342864562Sgshapiro hostbuf); 342938032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 343038032Speter hostbuf); 343138032Speter } 343238032Speter } 343364562Sgshapiro return hp; 343438032Speter} 343590792Sgshapiro/* 343638032Speter** ADDRCMP -- compare two host addresses 343738032Speter** 343838032Speter** Parameters: 343938032Speter** hp -- hostent structure for the first address 344038032Speter** ha -- actual first address 344138032Speter** sa -- second address 344238032Speter** 344338032Speter** Returns: 344438032Speter** 0 -- if ha and sa match 344538032Speter** else -- they don't match 344638032Speter*/ 344738032Speter 344864562Sgshapirostatic int 344938032Speteraddrcmp(hp, ha, sa) 345038032Speter struct hostent *hp; 345138032Speter char *ha; 345238032Speter SOCKADDR *sa; 345338032Speter{ 345490792Sgshapiro#if NETINET6 345590792Sgshapiro unsigned char *a; 3456363466Sgshapiro#endif 345764562Sgshapiro 345838032Speter switch (sa->sa.sa_family) 345938032Speter { 346090792Sgshapiro#if NETINET 346138032Speter case AF_INET: 346238032Speter if (hp->h_addrtype == AF_INET) 346364562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 346438032Speter break; 3465363466Sgshapiro#endif 346638032Speter 346790792Sgshapiro#if NETINET6 346864562Sgshapiro case AF_INET6: 346990792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 347064562Sgshapiro 347164562Sgshapiro /* Straight binary comparison */ 347264562Sgshapiro if (hp->h_addrtype == AF_INET6) 347364562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 347464562Sgshapiro 347564562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 347664562Sgshapiro if (hp->h_addrtype == AF_INET && 347764562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 347864562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 347964562Sgshapiro break; 348090792Sgshapiro#endif /* NETINET6 */ 348138032Speter } 348238032Speter return -1; 348338032Speter} 348490792Sgshapiro/* 348564562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 348638032Speter** 348738032Speter** Uses RFC1413 protocol to try to get info from the other end. 348838032Speter** 348938032Speter** Parameters: 349038032Speter** fd -- the descriptor 349190792Sgshapiro** may_be_forged -- an outage that is set to true if the 349238032Speter** forward lookup of RealHostName does not match 349390792Sgshapiro** RealHostAddr; set to false if they do match. 349438032Speter** 349538032Speter** Returns: 349638032Speter** The user@host information associated with this descriptor. 349738032Speter*/ 349838032Speter 349938032Speterstatic jmp_buf CtxAuthTimeout; 350038032Speter 350138032Speterstatic void 3502141858Sgshapiroauthtimeout(ignore) 3503141858Sgshapiro int ignore; 350438032Speter{ 350577349Sgshapiro /* 350677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 350777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 350877349Sgshapiro ** DOING. 350977349Sgshapiro */ 351077349Sgshapiro 351177349Sgshapiro errno = ETIMEDOUT; 351238032Speter longjmp(CtxAuthTimeout, 1); 351338032Speter} 351438032Speter 351538032Speterchar * 351638032Spetergetauthinfo(fd, may_be_forged) 351738032Speter int fd; 351838032Speter bool *may_be_forged; 351938032Speter{ 352090792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 352138032Speter SOCKADDR_LEN_T falen; 352238032Speter register char *volatile p = NULL; 352338032Speter SOCKADDR la; 352438032Speter SOCKADDR_LEN_T lalen; 352590792Sgshapiro#ifndef NO_GETSERVBYNAME 352638032Speter register struct servent *sp; 352790792Sgshapiro# if NETINET 352890792Sgshapiro static unsigned short port4 = 0; 3529363466Sgshapiro# endif 353090792Sgshapiro# if NETINET6 353190792Sgshapiro static unsigned short port6 = 0; 3532363466Sgshapiro# endif 353390792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 353438032Speter volatile int s; 353538032Speter int i = 0; 353690792Sgshapiro size_t len; 353790792Sgshapiro SM_EVENT *ev; 353838032Speter int nleft; 353938032Speter struct hostent *hp; 354038032Speter char *ostype = NULL; 354138032Speter char **ha; 354238032Speter char ibuf[MAXNAME + 1]; 3543110560Sgshapiro static char hbuf[MAXNAME + MAXAUTHINFO + 11]; 354438032Speter 3545285229Sgshapiro *may_be_forged = true; 3546168515Sgshapiro falen = sizeof(RealHostAddr); 354738032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 354838032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 354938032Speter { 355064562Sgshapiro if (i < 0) 355164562Sgshapiro { 355264562Sgshapiro /* 355364562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 355464562Sgshapiro ** errno in this case, so a mis-report doesn't 355564562Sgshapiro ** happen later. 355664562Sgshapiro */ 355790792Sgshapiro 355864562Sgshapiro if (errno != ENOTSOCK) 355964562Sgshapiro return NULL; 356064562Sgshapiro errno = 0; 356164562Sgshapiro } 3562285229Sgshapiro 3563285229Sgshapiro *may_be_forged = false; 3564168515Sgshapiro (void) sm_strlcpyn(hbuf, sizeof(hbuf), 2, RealUserName, 356590792Sgshapiro "@localhost"); 356638032Speter if (tTd(9, 1)) 356790792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 356838032Speter return hbuf; 356938032Speter } 357038032Speter 357138032Speter if (RealHostName == NULL) 357238032Speter { 357338032Speter /* translate that to a host name */ 357438032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 357538032Speter if (strlen(RealHostName) > MAXNAME) 357690792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 357738032Speter } 357838032Speter 357938032Speter /* cross check RealHostName with forward DNS lookup */ 3580285229Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] == '[' || 3581285229Sgshapiro RealHostName[0] == '[') 3582285229Sgshapiro *may_be_forged = false; 3583285229Sgshapiro else 358438032Speter { 358580785Sgshapiro int family; 358680785Sgshapiro 358780785Sgshapiro family = RealHostAddr.sa.sa_family; 358890792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 358980785Sgshapiro /* 359080785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 359180785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 359280785Sgshapiro ** address(es) for addrcmp() to compare against 359380785Sgshapiro ** RealHostAddr. 359480785Sgshapiro ** 359580785Sgshapiro ** Actually, we only need to do this for systems 359680785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 359780785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 359880785Sgshapiro ** flag. A better fix to this problem is to add this 359980785Sgshapiro ** functionality to our stub getipnodebyname(). 360080785Sgshapiro */ 360180785Sgshapiro 360280785Sgshapiro if (family == AF_INET6 && 360380785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 360480785Sgshapiro family = AF_INET; 360590792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 360680785Sgshapiro 360738032Speter /* try to match the reverse against the forward lookup */ 360880785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 3609285229Sgshapiro if (hp != NULL) 3610120256Sgshapiro { 361138032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 361290792Sgshapiro { 361338032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 3614285229Sgshapiro { 3615285229Sgshapiro *may_be_forged = false; 361638032Speter break; 3617285229Sgshapiro } 361890792Sgshapiro } 3619363466Sgshapiro FREEHOSTENT(hp, NULL); 362038032Speter } 362138032Speter } 362238032Speter 362338032Speter if (TimeOuts.to_ident == 0) 362438032Speter goto noident; 362538032Speter 3626168515Sgshapiro lalen = sizeof(la); 362764562Sgshapiro switch (RealHostAddr.sa.sa_family) 362838032Speter { 362990792Sgshapiro#if NETINET 363064562Sgshapiro case AF_INET: 363164562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 363264562Sgshapiro lalen <= 0 || 363364562Sgshapiro la.sa.sa_family != AF_INET) 363464562Sgshapiro { 363564562Sgshapiro /* no ident info */ 363664562Sgshapiro goto noident; 363764562Sgshapiro } 363864562Sgshapiro port = RealHostAddr.sin.sin_port; 363938032Speter 364064562Sgshapiro /* create ident query */ 3641168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 364264562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 364364562Sgshapiro ntohs(la.sin.sin_port)); 364438032Speter 364564562Sgshapiro /* create local address */ 364664562Sgshapiro la.sin.sin_port = 0; 364738032Speter 364864562Sgshapiro /* create foreign address */ 364990792Sgshapiro# ifdef NO_GETSERVBYNAME 365038032Speter RealHostAddr.sin.sin_port = htons(113); 365190792Sgshapiro# else /* NO_GETSERVBYNAME */ 365290792Sgshapiro 365390792Sgshapiro /* 365490792Sgshapiro ** getservbyname() consumes about 5% of the time 365590792Sgshapiro ** when receiving a small message (almost all of the time 365690792Sgshapiro ** spent in this routine). 365790792Sgshapiro ** Hence we store the port in a static variable 365890792Sgshapiro ** to save this time. 365990792Sgshapiro ** The portnumber shouldn't change very often... 366090792Sgshapiro ** This code makes the assumption that the port number 366190792Sgshapiro ** is not 0. 366290792Sgshapiro */ 366390792Sgshapiro 366490792Sgshapiro if (port4 == 0) 366590792Sgshapiro { 366690792Sgshapiro sp = getservbyname("auth", "tcp"); 366790792Sgshapiro if (sp != NULL) 366890792Sgshapiro port4 = sp->s_port; 366990792Sgshapiro else 367090792Sgshapiro port4 = htons(113); 367190792Sgshapiro } 367290792Sgshapiro RealHostAddr.sin.sin_port = port4; 367364562Sgshapiro break; 367490792Sgshapiro# endif /* NO_GETSERVBYNAME */ 367590792Sgshapiro#endif /* NETINET */ 367638032Speter 367790792Sgshapiro#if NETINET6 367864562Sgshapiro case AF_INET6: 367964562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 368064562Sgshapiro lalen <= 0 || 368164562Sgshapiro la.sa.sa_family != AF_INET6) 368264562Sgshapiro { 368364562Sgshapiro /* no ident info */ 368464562Sgshapiro goto noident; 368564562Sgshapiro } 368664562Sgshapiro port = RealHostAddr.sin6.sin6_port; 368764562Sgshapiro 368864562Sgshapiro /* create ident query */ 3689168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 369064562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 369164562Sgshapiro ntohs(la.sin6.sin6_port)); 369264562Sgshapiro 369364562Sgshapiro /* create local address */ 369464562Sgshapiro la.sin6.sin6_port = 0; 369564562Sgshapiro 369664562Sgshapiro /* create foreign address */ 369790792Sgshapiro# ifdef NO_GETSERVBYNAME 369864562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 369990792Sgshapiro# else /* NO_GETSERVBYNAME */ 370090792Sgshapiro if (port6 == 0) 370190792Sgshapiro { 370290792Sgshapiro sp = getservbyname("auth", "tcp"); 370390792Sgshapiro if (sp != NULL) 370490792Sgshapiro port6 = sp->s_port; 370590792Sgshapiro else 370690792Sgshapiro port6 = htons(113); 370790792Sgshapiro } 370890792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 370964562Sgshapiro break; 371090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 371190792Sgshapiro#endif /* NETINET6 */ 371264562Sgshapiro default: 371364562Sgshapiro /* no ident info */ 371464562Sgshapiro goto noident; 371564562Sgshapiro } 371664562Sgshapiro 371738032Speter s = -1; 371838032Speter if (setjmp(CtxAuthTimeout) != 0) 371938032Speter { 372038032Speter if (s >= 0) 372138032Speter (void) close(s); 372238032Speter goto noident; 372338032Speter } 372438032Speter 372538032Speter /* put a timeout around the whole thing */ 372690792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 372738032Speter 372838032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 372964562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 373038032Speter if (s < 0) 373138032Speter { 373290792Sgshapiro sm_clrevent(ev); 373338032Speter goto noident; 373438032Speter } 373564562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 373664562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 373738032Speter goto closeident; 373838032Speter 373938032Speter if (tTd(9, 10)) 374090792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 374138032Speter 374238032Speter /* send query */ 374338032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 374438032Speter goto closeident; 374538032Speter 374638032Speter /* get result */ 374738032Speter p = &ibuf[0]; 3748168515Sgshapiro nleft = sizeof(ibuf) - 1; 374938032Speter while ((i = read(s, p, nleft)) > 0) 375038032Speter { 3751125820Sgshapiro char *s; 3752125820Sgshapiro 375338032Speter p += i; 375438032Speter nleft -= i; 375538032Speter *p = '\0'; 3756125820Sgshapiro if ((s = strchr(ibuf, '\n')) != NULL) 3757125820Sgshapiro { 3758125820Sgshapiro if (p > s + 1) 3759125820Sgshapiro { 3760125820Sgshapiro p = s + 1; 3761125820Sgshapiro *p = '\0'; 3762125820Sgshapiro } 376338032Speter break; 3764125820Sgshapiro } 3765125820Sgshapiro if (nleft <= 0) 3766125820Sgshapiro break; 376738032Speter } 376838032Speter (void) close(s); 376990792Sgshapiro sm_clrevent(ev); 377038032Speter if (i < 0 || p == &ibuf[0]) 377138032Speter goto noident; 377238032Speter 3773111823Sgshapiro if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r') 377438032Speter p--; 377538032Speter *++p = '\0'; 377638032Speter 377738032Speter if (tTd(9, 3)) 377890792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 377938032Speter 378038032Speter /* parse result */ 378138032Speter p = strchr(ibuf, ':'); 378238032Speter if (p == NULL) 378338032Speter { 378438032Speter /* malformed response */ 378538032Speter goto noident; 378638032Speter } 378738032Speter while (isascii(*++p) && isspace(*p)) 378838032Speter continue; 378990792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 379038032Speter { 379138032Speter /* presumably an error string */ 379238032Speter goto noident; 379338032Speter } 379438032Speter p += 6; 3795363466Sgshapiro while (SM_ISSPACE(*p)) 379638032Speter p++; 379738032Speter if (*p++ != ':') 379838032Speter { 379938032Speter /* either useridxx or malformed response */ 380038032Speter goto noident; 380138032Speter } 380238032Speter 380338032Speter /* p now points to the OSTYPE field */ 3804363466Sgshapiro while (SM_ISSPACE(*p)) 380538032Speter p++; 380638032Speter ostype = p; 380738032Speter p = strchr(p, ':'); 380838032Speter if (p == NULL) 380938032Speter { 381038032Speter /* malformed response */ 381138032Speter goto noident; 381238032Speter } 381338032Speter else 381438032Speter { 381538032Speter char *charset; 381638032Speter 381738032Speter *p = '\0'; 381838032Speter charset = strchr(ostype, ','); 381938032Speter if (charset != NULL) 382038032Speter *charset = '\0'; 382138032Speter } 382238032Speter 382338032Speter /* 1413 says don't do this -- but it's broken otherwise */ 382438032Speter while (isascii(*++p) && isspace(*p)) 382538032Speter continue; 382638032Speter 382738032Speter /* p now points to the authenticated name -- copy carefully */ 382890792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 382938032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 383038032Speter { 3831168515Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof(hbuf)); 3832110560Sgshapiro cleanstrcpy(&hbuf[6], p, MAXAUTHINFO); 383338032Speter } 383438032Speter else 3835110560Sgshapiro cleanstrcpy(hbuf, p, MAXAUTHINFO); 383690792Sgshapiro len = strlen(hbuf); 3837168515Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof(hbuf) - len, 2, "@", 383890792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 383938032Speter goto postident; 384038032Speter 384138032Spetercloseident: 384238032Speter (void) close(s); 384390792Sgshapiro sm_clrevent(ev); 384438032Speter 384538032Speternoident: 384664562Sgshapiro /* put back the original incoming port */ 384764562Sgshapiro switch (RealHostAddr.sa.sa_family) 384864562Sgshapiro { 384990792Sgshapiro#if NETINET 385064562Sgshapiro case AF_INET: 385164562Sgshapiro if (port > 0) 385264562Sgshapiro RealHostAddr.sin.sin_port = port; 385364562Sgshapiro break; 385490792Sgshapiro#endif /* NETINET */ 385564562Sgshapiro 385690792Sgshapiro#if NETINET6 385764562Sgshapiro case AF_INET6: 385864562Sgshapiro if (port > 0) 385964562Sgshapiro RealHostAddr.sin6.sin6_port = port; 386064562Sgshapiro break; 386190792Sgshapiro#endif /* NETINET6 */ 386264562Sgshapiro } 386364562Sgshapiro 386438032Speter if (RealHostName == NULL) 386538032Speter { 386638032Speter if (tTd(9, 1)) 386790792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 386838032Speter return NULL; 386938032Speter } 3870168515Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof(hbuf)); 387138032Speter 387238032Speterpostident: 387390792Sgshapiro#if IP_SRCROUTE 387490792Sgshapiro# ifndef GET_IPOPT_DST 387590792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 3876363466Sgshapiro# endif 387738032Speter /* 387838032Speter ** Extract IP source routing information. 387938032Speter ** 388038032Speter ** Format of output for a connection from site a through b 388138032Speter ** through c to d: 388238032Speter ** loose: @site-c@site-b:site-a 388338032Speter ** strict: !@site-c@site-b:site-a 388438032Speter ** 388538032Speter ** o - pointer within ipopt_list structure. 388638032Speter ** q - pointer within ls/ss rr route data 388738032Speter ** p - pointer to hbuf 388838032Speter */ 388938032Speter 389038032Speter if (RealHostAddr.sa.sa_family == AF_INET) 389138032Speter { 389238032Speter SOCKOPT_LEN_T ipoptlen; 389338032Speter int j; 389490792Sgshapiro unsigned char *q; 389590792Sgshapiro unsigned char *o; 389638032Speter int l; 389764562Sgshapiro struct IPOPTION ipopt; 389838032Speter 3899168515Sgshapiro ipoptlen = sizeof(ipopt); 390038032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 390138032Speter (char *) &ipopt, &ipoptlen) < 0) 390238032Speter goto noipsr; 390338032Speter if (ipoptlen == 0) 390438032Speter goto noipsr; 390590792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 390690792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 390738032Speter { 390838032Speter switch (*o) 390938032Speter { 391064562Sgshapiro case IPOPT_EOL: 391138032Speter o = NULL; 391238032Speter break; 391338032Speter 391438032Speter case IPOPT_NOP: 391538032Speter o++; 391638032Speter break; 391738032Speter 391838032Speter case IPOPT_SSRR: 391938032Speter case IPOPT_LSRR: 392038032Speter /* 392138032Speter ** Source routing. 392238032Speter ** o[0] is the option type (loose/strict). 392338032Speter ** o[1] is the length of this option, 392438032Speter ** including option type and 392538032Speter ** length. 392638032Speter ** o[2] is the pointer into the route 392738032Speter ** data. 392838032Speter ** o[3] begins the route data. 392938032Speter */ 393038032Speter 393138032Speter p = &hbuf[strlen(hbuf)]; 3932168515Sgshapiro l = sizeof(hbuf) - (hbuf - p) - 6; 393390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 393490792Sgshapiro " [%s@%.*s", 393590792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 393690792Sgshapiro l > 240 ? 120 : l / 2, 393790792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 393838032Speter i = strlen(p); 393938032Speter p += i; 394038032Speter l -= strlen(p); 394138032Speter 394238032Speter j = o[1] / sizeof(struct in_addr) - 1; 394338032Speter 394438032Speter /* q skips length and router pointer to data */ 394538032Speter q = &o[3]; 394638032Speter for ( ; j >= 0; j--) 394738032Speter { 394864562Sgshapiro struct in_addr addr; 394964562Sgshapiro 395038032Speter memcpy(&addr, q, sizeof(addr)); 395190792Sgshapiro (void) sm_snprintf(p, 395290792Sgshapiro SPACELEFT(hbuf, p), 395390792Sgshapiro "%c%.*s", 395490792Sgshapiro j != 0 ? '@' : ':', 395590792Sgshapiro l > 240 ? 120 : 395690792Sgshapiro j == 0 ? l : l / 2, 395790792Sgshapiro inet_ntoa(addr)); 395838032Speter i = strlen(p); 395938032Speter p += i; 396038032Speter l -= i + 1; 396164562Sgshapiro q += sizeof(struct in_addr); 396238032Speter } 396338032Speter o += o[1]; 396438032Speter break; 396538032Speter 396638032Speter default: 396738032Speter /* Skip over option */ 396838032Speter o += o[1]; 396938032Speter break; 397038032Speter } 397138032Speter } 397290792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 397338032Speter goto postipsr; 397438032Speter } 397538032Speter 397638032Speternoipsr: 397790792Sgshapiro#endif /* IP_SRCROUTE */ 397838032Speter if (RealHostName != NULL && RealHostName[0] != '[') 397938032Speter { 398038032Speter p = &hbuf[strlen(hbuf)]; 398190792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 398290792Sgshapiro anynet_ntoa(&RealHostAddr)); 398338032Speter } 398438032Speter if (*may_be_forged) 398538032Speter { 398638032Speter p = &hbuf[strlen(hbuf)]; 398790792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 398890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 398990792Sgshapiro macid("{client_resolve}"), "FORGED"); 399038032Speter } 399138032Speter 399290792Sgshapiro#if IP_SRCROUTE 399338032Speterpostipsr: 399490792Sgshapiro#endif /* IP_SRCROUTE */ 399564562Sgshapiro 399664562Sgshapiro /* put back the original incoming port */ 399764562Sgshapiro switch (RealHostAddr.sa.sa_family) 399864562Sgshapiro { 399990792Sgshapiro#if NETINET 400064562Sgshapiro case AF_INET: 400164562Sgshapiro if (port > 0) 400264562Sgshapiro RealHostAddr.sin.sin_port = port; 400364562Sgshapiro break; 400490792Sgshapiro#endif /* NETINET */ 400564562Sgshapiro 400690792Sgshapiro#if NETINET6 400764562Sgshapiro case AF_INET6: 400864562Sgshapiro if (port > 0) 400964562Sgshapiro RealHostAddr.sin6.sin6_port = port; 401064562Sgshapiro break; 401190792Sgshapiro#endif /* NETINET6 */ 401264562Sgshapiro } 401364562Sgshapiro 401490792Sgshapiro if (tTd(9, 1)) 401590792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 401638032Speter return hbuf; 401738032Speter} 401890792Sgshapiro/* 401938032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 402038032Speter** 402138032Speter** Parameters: 402238032Speter** map -- a pointer to this map. 402338032Speter** name -- the (presumably unqualified) hostname. 402438032Speter** av -- unused -- for compatibility with other mapping 402538032Speter** functions. 402638032Speter** statp -- an exit status (out parameter) -- set to 402738032Speter** EX_TEMPFAIL if the name server is unavailable. 402838032Speter** 402938032Speter** Returns: 403038032Speter** The mapping, if found. 403138032Speter** NULL if no mapping found. 403238032Speter** 403338032Speter** Side Effects: 403438032Speter** Looks up the host specified in hbuf. If it is not 403538032Speter** the canonical name for that host, return the canonical 403638032Speter** name (unless MF_MATCHONLY is set, which will cause the 403738032Speter** status only to be returned). 403838032Speter*/ 403938032Speter 404038032Speterchar * 404138032Speterhost_map_lookup(map, name, av, statp) 404238032Speter MAP *map; 404338032Speter char *name; 404438032Speter char **av; 404538032Speter int *statp; 404638032Speter{ 404738032Speter register struct hostent *hp; 404890792Sgshapiro#if NETINET 404938032Speter struct in_addr in_addr; 4050363466Sgshapiro#endif 405190792Sgshapiro#if NETINET6 405264562Sgshapiro struct in6_addr in6_addr; 4053363466Sgshapiro#endif 405464562Sgshapiro char *cp, *ans = NULL; 405538032Speter register STAB *s; 405690792Sgshapiro time_t now; 405790792Sgshapiro#if NAMED_BIND 405890792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 405990792Sgshapiro int SM_NONVOLATILE retry = 0; 4060363466Sgshapiro#endif 406138032Speter char hbuf[MAXNAME + 1]; 406238032Speter 406338032Speter /* 406438032Speter ** See if we have already looked up this name. If so, just 406590792Sgshapiro ** return it (unless expired). 406638032Speter */ 406738032Speter 406890792Sgshapiro now = curtime(); 406938032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 407090792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 407190792Sgshapiro s->s_namecanon.nc_exp >= now) 407238032Speter { 407338032Speter if (tTd(9, 1)) 407490792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 407590792Sgshapiro name, 407690792Sgshapiro s->s_namecanon.nc_cname == NULL 407738032Speter ? "NULL" 407838032Speter : s->s_namecanon.nc_cname); 407938032Speter errno = s->s_namecanon.nc_errno; 408073188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 408138032Speter *statp = s->s_namecanon.nc_stat; 408238032Speter if (*statp == EX_TEMPFAIL) 408338032Speter { 408438032Speter CurEnv->e_status = "4.4.3"; 408538032Speter message("851 %s: Name server timeout", 408638032Speter shortenstring(name, 33)); 408738032Speter } 408838032Speter if (*statp != EX_OK) 408938032Speter return NULL; 409038032Speter if (s->s_namecanon.nc_cname == NULL) 409138032Speter { 4092132943Sgshapiro syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d", 409364562Sgshapiro name, 409464562Sgshapiro s->s_namecanon.nc_errno, 409564562Sgshapiro s->s_namecanon.nc_herrno); 409638032Speter return NULL; 409738032Speter } 4098363466Sgshapiro if (bitset(NCF_SECURE, s->s_namecanon.nc_flags)) 4099363466Sgshapiro map->map_mflags |= MF_SECURE; 4100363466Sgshapiro else 4101363466Sgshapiro map->map_mflags &= ~MF_SECURE; 410238032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 410338032Speter cp = map_rewrite(map, name, strlen(name), NULL); 410438032Speter else 410538032Speter cp = map_rewrite(map, 410638032Speter s->s_namecanon.nc_cname, 410738032Speter strlen(s->s_namecanon.nc_cname), 410838032Speter av); 410938032Speter return cp; 411038032Speter } 411138032Speter 411238032Speter /* 411338032Speter ** If we are running without a regular network connection (usually 411438032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 411538032Speter ** lookups because those could try to connect to a server. 411638032Speter */ 411738032Speter 411864562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 411964562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 412038032Speter { 412138032Speter if (tTd(9, 1)) 412290792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 412338032Speter *statp = EX_TEMPFAIL; 412438032Speter return NULL; 412538032Speter } 412638032Speter 412738032Speter /* 412838032Speter ** If first character is a bracket, then it is an address 412938032Speter ** lookup. Address is copied into a temporary buffer to 413038032Speter ** strip the brackets and to preserve name if address is 413138032Speter ** unknown. 413238032Speter */ 413338032Speter 413464562Sgshapiro if (tTd(9, 1)) 413590792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 413690792Sgshapiro#if NAMED_BIND 413790792Sgshapiro if (map->map_timeout > 0) 413890792Sgshapiro { 413990792Sgshapiro retrans = _res.retrans; 414090792Sgshapiro _res.retrans = map->map_timeout; 414190792Sgshapiro } 414290792Sgshapiro if (map->map_retry > 0) 414390792Sgshapiro { 414490792Sgshapiro retry = _res.retry; 414590792Sgshapiro _res.retry = map->map_retry; 414690792Sgshapiro } 414790792Sgshapiro#endif /* NAMED_BIND */ 414890792Sgshapiro 414990792Sgshapiro /* set default TTL */ 415090792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 415138032Speter if (*name != '[') 415238032Speter { 4153363466Sgshapiro int ttl, r; 415490792Sgshapiro 4155168515Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof(hbuf)); 4156363466Sgshapiro 4157363466Sgshapiro r = getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl); 4158363466Sgshapiro if (r != HOST_NOTFOUND) 415990792Sgshapiro { 416064562Sgshapiro ans = hbuf; 416190792Sgshapiro if (ttl > 0) 416290792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 416390792Sgshapiro SM_DEFAULT_TTL); 4164363466Sgshapiro 4165363466Sgshapiro if (HOST_SECURE == r) 4166363466Sgshapiro { 4167363466Sgshapiro s->s_namecanon.nc_flags |= NCF_SECURE; 4168363466Sgshapiro map->map_mflags |= MF_SECURE; 4169363466Sgshapiro } 4170363466Sgshapiro else 4171363466Sgshapiro { 4172363466Sgshapiro s->s_namecanon.nc_flags &= ~NCF_SECURE; 4173363466Sgshapiro map->map_mflags &= ~MF_SECURE; 4174363466Sgshapiro } 417590792Sgshapiro } 417664562Sgshapiro } 417764562Sgshapiro else 417864562Sgshapiro { 417964562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 418071345Sgshapiro { 418171345Sgshapiro if (tTd(9, 1)) 418290792Sgshapiro sm_dprintf("FAILED\n"); 418364562Sgshapiro return NULL; 418471345Sgshapiro } 418564562Sgshapiro *cp = '\0'; 418664562Sgshapiro 418764562Sgshapiro hp = NULL; 4188363466Sgshapiro 4189363466Sgshapiro /* should this be considered secure? */ 4190363466Sgshapiro map->map_mflags &= ~MF_SECURE; 419190792Sgshapiro#if NETINET 419264562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 419364562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 419464562Sgshapiro INADDRSZ, AF_INET); 419590792Sgshapiro#endif /* NETINET */ 419690792Sgshapiro#if NETINET6 419764562Sgshapiro if (hp == NULL && 419890792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 419964562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 420064562Sgshapiro IN6ADDRSZ, AF_INET6); 420190792Sgshapiro#endif /* NETINET6 */ 420264562Sgshapiro *cp = ']'; 420364562Sgshapiro 420464562Sgshapiro if (hp != NULL) 420538032Speter { 420664562Sgshapiro /* found a match -- copy out */ 420790792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 420890792Sgshapiro#if NETINET6 420990792Sgshapiro if (ans == hp->h_name) 421090792Sgshapiro { 421190792Sgshapiro static char n[MAXNAME + 1]; 421290792Sgshapiro 421390792Sgshapiro /* hp->h_name is about to disappear */ 4214168515Sgshapiro (void) sm_strlcpy(n, ans, sizeof(n)); 421590792Sgshapiro ans = n; 421690792Sgshapiro } 4217363466Sgshapiro FREEHOSTENT(hp, NULL); 421890792Sgshapiro#endif /* NETINET6 */ 421938032Speter } 422064562Sgshapiro } 422190792Sgshapiro#if NAMED_BIND 422290792Sgshapiro if (map->map_timeout > 0) 422390792Sgshapiro _res.retrans = retrans; 422490792Sgshapiro if (map->map_retry > 0) 422590792Sgshapiro _res.retry = retry; 422690792Sgshapiro#endif /* NAMED_BIND */ 422738032Speter 422864562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 422938032Speter 423064562Sgshapiro /* Found an answer */ 423164562Sgshapiro if (ans != NULL) 423264562Sgshapiro { 423364562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 423490792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 423590792Sgshapiro sm_free(s->s_namecanon.nc_cname); 423690792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 423764562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 423864562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 423964562Sgshapiro else 424064562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 424171345Sgshapiro if (tTd(9, 1)) 424290792Sgshapiro sm_dprintf("FOUND %s\n", ans); 424364562Sgshapiro return cp; 424438032Speter } 424538032Speter 424664562Sgshapiro 424764562Sgshapiro /* No match found */ 424838032Speter s->s_namecanon.nc_errno = errno; 424990792Sgshapiro#if NAMED_BIND 425038032Speter s->s_namecanon.nc_herrno = h_errno; 425164562Sgshapiro if (tTd(9, 1)) 425290792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 425364562Sgshapiro switch (h_errno) 425438032Speter { 425564562Sgshapiro case TRY_AGAIN: 425664562Sgshapiro if (UseNameServer) 425764562Sgshapiro { 425864562Sgshapiro CurEnv->e_status = "4.4.3"; 425964562Sgshapiro message("851 %s: Name server timeout", 426064562Sgshapiro shortenstring(name, 33)); 426164562Sgshapiro } 426264562Sgshapiro *statp = EX_TEMPFAIL; 426364562Sgshapiro break; 426464562Sgshapiro 426564562Sgshapiro case HOST_NOT_FOUND: 426664562Sgshapiro case NO_DATA: 426764562Sgshapiro *statp = EX_NOHOST; 426864562Sgshapiro break; 426964562Sgshapiro 427064562Sgshapiro case NO_RECOVERY: 427164562Sgshapiro *statp = EX_SOFTWARE; 427264562Sgshapiro break; 427364562Sgshapiro 427464562Sgshapiro default: 427564562Sgshapiro *statp = EX_UNAVAILABLE; 427664562Sgshapiro break; 427738032Speter } 427890792Sgshapiro#else /* NAMED_BIND */ 427964562Sgshapiro if (tTd(9, 1)) 428090792Sgshapiro sm_dprintf("FAIL\n"); 428164562Sgshapiro *statp = EX_NOHOST; 428290792Sgshapiro#endif /* NAMED_BIND */ 428364562Sgshapiro s->s_namecanon.nc_stat = *statp; 428464562Sgshapiro return NULL; 428538032Speter} 428638032Speter/* 428790792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 428838032Speter** 428938032Speter** Parameters: 429090792Sgshapiro** map -- a pointer to this map. 429190792Sgshapiro** args -- argument string. 429238032Speter** 429338032Speter** Returns: 429490792Sgshapiro** true. 429538032Speter*/ 429638032Speter 429738032Speterbool 429838032Speterhost_map_init(map, args) 429938032Speter MAP *map; 430038032Speter char *args; 430138032Speter{ 430238032Speter register char *p = args; 430338032Speter 430438032Speter for (;;) 430538032Speter { 4306363466Sgshapiro while (SM_ISSPACE(*p)) 430738032Speter p++; 430838032Speter if (*p != '-') 430938032Speter break; 431038032Speter switch (*++p) 431138032Speter { 431238032Speter case 'a': 431338032Speter map->map_app = ++p; 431438032Speter break; 431538032Speter 431638032Speter case 'T': 431738032Speter map->map_tapp = ++p; 431838032Speter break; 431938032Speter 432038032Speter case 'm': 432138032Speter map->map_mflags |= MF_MATCHONLY; 432238032Speter break; 432338032Speter 432438032Speter case 't': 432538032Speter map->map_mflags |= MF_NODEFER; 432638032Speter break; 432764562Sgshapiro 432864562Sgshapiro case 'S': /* only for consistency */ 432964562Sgshapiro map->map_spacesub = *++p; 433064562Sgshapiro break; 433164562Sgshapiro 433264562Sgshapiro case 'D': 433364562Sgshapiro map->map_mflags |= MF_DEFER; 433464562Sgshapiro break; 433590792Sgshapiro 433690792Sgshapiro case 'd': 433790792Sgshapiro { 433890792Sgshapiro char *h; 433990792Sgshapiro 434090792Sgshapiro while (isascii(*++p) && isspace(*p)) 434190792Sgshapiro continue; 434290792Sgshapiro h = strchr(p, ' '); 434390792Sgshapiro if (h != NULL) 434490792Sgshapiro *h = '\0'; 434590792Sgshapiro map->map_timeout = convtime(p, 's'); 434690792Sgshapiro if (h != NULL) 434790792Sgshapiro *h = ' '; 434890792Sgshapiro } 434990792Sgshapiro break; 435090792Sgshapiro 435190792Sgshapiro case 'r': 435290792Sgshapiro while (isascii(*++p) && isspace(*p)) 435390792Sgshapiro continue; 435490792Sgshapiro map->map_retry = atoi(p); 435590792Sgshapiro break; 435638032Speter } 4357363466Sgshapiro while (*p != '\0' && !(SM_ISSPACE(*p))) 435838032Speter p++; 435938032Speter if (*p != '\0') 436038032Speter *p++ = '\0'; 436138032Speter } 436238032Speter if (map->map_app != NULL) 436338032Speter map->map_app = newstr(map->map_app); 436438032Speter if (map->map_tapp != NULL) 436538032Speter map->map_tapp = newstr(map->map_tapp); 436690792Sgshapiro return true; 436738032Speter} 436890792Sgshapiro 436964562Sgshapiro#if NETINET6 437064562Sgshapiro/* 437164562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 437264562Sgshapiro** 437364562Sgshapiro** Parameters: 437464562Sgshapiro** s6a -- a pointer to an in6_addr structure. 437564562Sgshapiro** dst -- buffer to store result in 437664562Sgshapiro** dst_len -- size of dst buffer 437764562Sgshapiro** 437864562Sgshapiro** Returns: 437964562Sgshapiro** A printable version of that structure. 438064562Sgshapiro*/ 438190792Sgshapiro 438264562Sgshapirochar * 438364562Sgshapiroanynet_ntop(s6a, dst, dst_len) 438464562Sgshapiro struct in6_addr *s6a; 438564562Sgshapiro char *dst; 438664562Sgshapiro size_t dst_len; 438764562Sgshapiro{ 438864562Sgshapiro register char *ap; 438964562Sgshapiro 439064562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 439164562Sgshapiro ap = (char *) inet_ntop(AF_INET, 439264562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 439364562Sgshapiro dst, dst_len); 439464562Sgshapiro else 439590792Sgshapiro { 439690792Sgshapiro char *d; 439790792Sgshapiro size_t sz; 439890792Sgshapiro 439990792Sgshapiro /* Save pointer to beginning of string */ 440090792Sgshapiro d = dst; 440190792Sgshapiro 440290792Sgshapiro /* Add IPv6: protocol tag */ 440390792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 440490792Sgshapiro if (sz >= dst_len) 440590792Sgshapiro return NULL; 440690792Sgshapiro dst += sz; 440790792Sgshapiro dst_len -= sz; 4408285229Sgshapiro if (UseCompressedIPv6Addresses) 4409285229Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 4410285229Sgshapiro else 4411285229Sgshapiro ap = sm_inet6_ntop(s6a, dst, dst_len); 441290792Sgshapiro /* Restore pointer to beginning of string */ 441390792Sgshapiro if (ap != NULL) 441490792Sgshapiro ap = d; 441590792Sgshapiro } 441664562Sgshapiro return ap; 441764562Sgshapiro} 441890792Sgshapiro 441990792Sgshapiro/* 442090792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 442190792Sgshapiro** 442290792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 442390792Sgshapiro** 442490792Sgshapiro** Parameters: 442590792Sgshapiro** family -- address family 442690792Sgshapiro** src -- string 442790792Sgshapiro** dst -- destination address structure 442890792Sgshapiro** 442990792Sgshapiro** Returns: 443090792Sgshapiro** 1 if the address was valid 4431363466Sgshapiro** 0 if the address wasn't parsable 443290792Sgshapiro** -1 if error 443390792Sgshapiro*/ 443490792Sgshapiro 443590792Sgshapiroint 443690792Sgshapiroanynet_pton(family, src, dst) 443790792Sgshapiro int family; 443890792Sgshapiro const char *src; 443990792Sgshapiro void *dst; 444090792Sgshapiro{ 444190792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 444290792Sgshapiro src += 5; 444390792Sgshapiro return inet_pton(family, src, dst); 444490792Sgshapiro} 444564562Sgshapiro#endif /* NETINET6 */ 444690792Sgshapiro/* 444738032Speter** ANYNET_NTOA -- convert a network address to printable form. 444838032Speter** 444938032Speter** Parameters: 445038032Speter** sap -- a pointer to a sockaddr structure. 445138032Speter** 445238032Speter** Returns: 445338032Speter** A printable version of that sockaddr. 445438032Speter*/ 445538032Speter 445638032Speter#ifdef USE_SOCK_STREAM 445738032Speter 445864562Sgshapiro# if NETLINK 445964562Sgshapiro# include <net/if_dl.h> 4460363466Sgshapiro# endif 446138032Speter 446238032Speterchar * 446338032Speteranynet_ntoa(sap) 446438032Speter register SOCKADDR *sap; 446538032Speter{ 446638032Speter register char *bp; 446738032Speter register char *ap; 446838032Speter int l; 446938032Speter static char buf[100]; 447038032Speter 447138032Speter /* check for null/zero family */ 447238032Speter if (sap == NULL) 447338032Speter return "NULLADDR"; 447438032Speter if (sap->sa.sa_family == 0) 447538032Speter return "0"; 447638032Speter 447738032Speter switch (sap->sa.sa_family) 447838032Speter { 447964562Sgshapiro# if NETUNIX 448038032Speter case AF_UNIX: 448164562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 4482168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[UNIX: %.64s]", 448390792Sgshapiro sap->sunix.sun_path); 448464562Sgshapiro else 4485168515Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof(buf)); 448638032Speter return buf; 448764562Sgshapiro# endif /* NETUNIX */ 448838032Speter 448964562Sgshapiro# if NETINET 449038032Speter case AF_INET: 449164562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 4492363466Sgshapiro# endif 449338032Speter 449464562Sgshapiro# if NETINET6 449564562Sgshapiro case AF_INET6: 4496168515Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof(buf)); 449764562Sgshapiro if (ap != NULL) 449864562Sgshapiro return ap; 449964562Sgshapiro break; 450064562Sgshapiro# endif /* NETINET6 */ 450164562Sgshapiro 450264562Sgshapiro# if NETLINK 450338032Speter case AF_LINK: 4504168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[LINK: %s]", 450590792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 450638032Speter return buf; 450764562Sgshapiro# endif /* NETLINK */ 450838032Speter default: 450938032Speter /* this case is needed when nothing is #defined */ 451038032Speter /* in order to keep the switch syntactically correct */ 451138032Speter break; 451238032Speter } 451338032Speter 451438032Speter /* unknown family -- just dump bytes */ 4515168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Family %d: ", sap->sa.sa_family); 451638032Speter bp = &buf[strlen(buf)]; 451738032Speter ap = sap->sa.sa_data; 4518168515Sgshapiro for (l = sizeof(sap->sa.sa_data); --l >= 0; ) 451938032Speter { 452090792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 452190792Sgshapiro *ap++ & 0377); 452238032Speter bp += 3; 452338032Speter } 452438032Speter *--bp = '\0'; 452538032Speter return buf; 452638032Speter} 452790792Sgshapiro/* 452838032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 452938032Speter** 453038032Speter** Parameters: 453138032Speter** sap -- SOCKADDR pointer 453238032Speter** 453338032Speter** Returns: 453438032Speter** text representation of host name. 453538032Speter** 453638032Speter** Side Effects: 453738032Speter** none. 453838032Speter*/ 453938032Speter 454038032Speterchar * 454138032Speterhostnamebyanyaddr(sap) 454238032Speter register SOCKADDR *sap; 454338032Speter{ 454438032Speter register struct hostent *hp; 454564562Sgshapiro# if NAMED_BIND 454638032Speter int saveretry; 4547363466Sgshapiro# endif 454864562Sgshapiro# if NETINET6 454964562Sgshapiro struct in6_addr in6_addr; 455064562Sgshapiro# endif /* NETINET6 */ 455138032Speter 455264562Sgshapiro# if NAMED_BIND 455338032Speter /* shorten name server timeout to avoid higher level timeouts */ 455438032Speter saveretry = _res.retry; 455564562Sgshapiro if (_res.retry * _res.retrans > 20) 455664562Sgshapiro _res.retry = 20 / _res.retrans; 4557244833Sgshapiro if (_res.retry == 0) 4558244833Sgshapiro _res.retry = 1; 455964562Sgshapiro# endif /* NAMED_BIND */ 456038032Speter 456138032Speter switch (sap->sa.sa_family) 456238032Speter { 456364562Sgshapiro# if NETINET 456438032Speter case AF_INET: 456538032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 456690792Sgshapiro INADDRSZ, AF_INET); 456738032Speter break; 456864562Sgshapiro# endif /* NETINET */ 456938032Speter 457064562Sgshapiro# if NETINET6 457164562Sgshapiro case AF_INET6: 457264562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 457390792Sgshapiro IN6ADDRSZ, AF_INET6); 457464562Sgshapiro break; 457564562Sgshapiro# endif /* NETINET6 */ 457664562Sgshapiro 457764562Sgshapiro# if NETISO 457838032Speter case AF_ISO: 457938032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 4580168515Sgshapiro sizeof(sap->siso.siso_addr), AF_ISO); 458138032Speter break; 458264562Sgshapiro# endif /* NETISO */ 458338032Speter 458464562Sgshapiro# if NETUNIX 458538032Speter case AF_UNIX: 458638032Speter hp = NULL; 458738032Speter break; 458864562Sgshapiro# endif /* NETUNIX */ 458938032Speter 459038032Speter default: 4591168515Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof(sap->sa.sa_data), 459290792Sgshapiro sap->sa.sa_family); 459338032Speter break; 459438032Speter } 459538032Speter 459664562Sgshapiro# if NAMED_BIND 459738032Speter _res.retry = saveretry; 4598363466Sgshapiro# endif 459938032Speter 460064562Sgshapiro# if NETINET || NETINET6 460164562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 460264562Sgshapiro# if NETINET6 460364562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 460464562Sgshapiro# endif /* NETINET6 */ 460564562Sgshapiro# if NETINET 460664562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 4607363466Sgshapiro# endif 460864562Sgshapiro ) 460971345Sgshapiro { 461071345Sgshapiro char *name; 461171345Sgshapiro 461290792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 461390792Sgshapiro# if NETINET6 461471345Sgshapiro if (name == hp->h_name) 461571345Sgshapiro { 461671345Sgshapiro static char n[MAXNAME + 1]; 461771345Sgshapiro 461871345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 4619168515Sgshapiro (void) sm_strlcpy(n, name, sizeof(n)); 462071345Sgshapiro name = n; 462171345Sgshapiro } 4622363466Sgshapiro FREEHOSTENT(hp, NULL); 462390792Sgshapiro# endif /* NETINET6 */ 462471345Sgshapiro return name; 462571345Sgshapiro } 462664562Sgshapiro# endif /* NETINET || NETINET6 */ 462771345Sgshapiro 4628363466Sgshapiro FREEHOSTENT(hp, NULL); 462971345Sgshapiro 463064562Sgshapiro# if NETUNIX 463164562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 463238032Speter return "localhost"; 4633363466Sgshapiro# endif 463438032Speter { 463538032Speter static char buf[203]; 463638032Speter 4637168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[%.200s]", 463890792Sgshapiro anynet_ntoa(sap)); 463938032Speter return buf; 464038032Speter } 464138032Speter} 464264562Sgshapiro#endif /* USE_SOCK_STREAM */ 4643