daemon.c revision 120256
138032Speter/* 2111823Sgshapiro * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1538032Speter 16120256SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.613.2.17 2003/07/30 20:17:04 ca Exp $") 1764562Sgshapiro 1838032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 1938032Speter# define USE_SOCK_STREAM 1 2064562Sgshapiro#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */ 2138032Speter 2290792Sgshapiro#if defined(USE_SOCK_STREAM) 2364562Sgshapiro# if NETINET || NETINET6 2464562Sgshapiro# include <arpa/inet.h> 2564562Sgshapiro# endif /* NETINET || NETINET6 */ 2638032Speter# if NAMED_BIND 2738032Speter# ifndef NO_DATA 2838032Speter# define NO_DATA NO_ADDRESS 2964562Sgshapiro# endif /* ! NO_DATA */ 3064562Sgshapiro# endif /* NAMED_BIND */ 3190792Sgshapiro#endif /* defined(USE_SOCK_STREAM) */ 3238032Speter 3390792Sgshapiro#if STARTTLS 3490792Sgshapiro# include <openssl/rand.h> 3590792Sgshapiro#endif /* STARTTLS */ 3638032Speter 3790792Sgshapiro#include <sys/time.h> 3866494Sgshapiro 3990792Sgshapiro#if IP_SRCROUTE && NETINET 4090792Sgshapiro# include <netinet/in_systm.h> 4190792Sgshapiro# include <netinet/ip.h> 4290792Sgshapiro# if HAS_IN_H 4390792Sgshapiro# include <netinet/in.h> 4490792Sgshapiro# ifndef IPOPTION 4590792Sgshapiro# define IPOPTION ip_opts 4690792Sgshapiro# define IP_LIST ip_opts 4790792Sgshapiro# define IP_DST ip_dst 4890792Sgshapiro# endif /* ! IPOPTION */ 4990792Sgshapiro# else /* HAS_IN_H */ 5090792Sgshapiro# include <netinet/ip_var.h> 5190792Sgshapiro# ifndef IPOPTION 5290792Sgshapiro# define IPOPTION ipoption 5390792Sgshapiro# define IP_LIST ipopt_list 5490792Sgshapiro# define IP_DST ipopt_dst 5590792Sgshapiro# endif /* ! IPOPTION */ 5690792Sgshapiro# endif /* HAS_IN_H */ 5790792Sgshapiro#endif /* IP_SRCROUTE && NETINET */ 5838032Speter 5990792Sgshapiro#include <sm/fdset.h> 6038032Speter 6190792Sgshapiro/* structure to describe a daemon or a client */ 6264562Sgshapirostruct daemon 6364562Sgshapiro{ 6464562Sgshapiro int d_socket; /* fd for socket */ 6564562Sgshapiro SOCKADDR d_addr; /* socket for incoming */ 6690792Sgshapiro unsigned short d_port; /* port number */ 6764562Sgshapiro int d_listenqueue; /* size of listen queue */ 6864562Sgshapiro int d_tcprcvbufsize; /* size of TCP receive buffer */ 6964562Sgshapiro int d_tcpsndbufsize; /* size of TCP send buffer */ 7064562Sgshapiro time_t d_refuse_connections_until; 7164562Sgshapiro bool d_firsttime; 7264562Sgshapiro int d_socksize; 7364562Sgshapiro BITMAP256 d_flags; /* flags; see sendmail.h */ 7464562Sgshapiro char *d_mflags; /* flags for use in macro */ 7564562Sgshapiro char *d_name; /* user-supplied name */ 7690792Sgshapiro#if MILTER 7790792Sgshapiro# if _FFR_MILTER_PERDAEMON 7890792Sgshapiro char *d_inputfilterlist; 7990792Sgshapiro struct milter *d_inputfilters[MAXFILTERS]; 8090792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 8190792Sgshapiro#endif /* MILTER */ 8264562Sgshapiro}; 8364562Sgshapiro 8464562Sgshapirotypedef struct daemon DAEMON_T; 8564562Sgshapiro 8690792Sgshapirostatic void connecttimeout __P((void)); 8790792Sgshapirostatic int opendaemonsocket __P((DAEMON_T *, bool)); 8890792Sgshapirostatic unsigned short setupdaemon __P((SOCKADDR *)); 8990792Sgshapirostatic void getrequests_checkdiskspace __P((ENVELOPE *e)); 9064562Sgshapiro 9138032Speter/* 9238032Speter** DAEMON.C -- routines to use when running as a daemon. 9338032Speter** 9438032Speter** This entire file is highly dependent on the 4.2 BSD 9538032Speter** interprocess communication primitives. No attempt has 9638032Speter** been made to make this file portable to Version 7, 9738032Speter** Version 6, MPX files, etc. If you should try such a 9838032Speter** thing yourself, I recommend chucking the entire file 9938032Speter** and starting from scratch. Basic semantics are: 10038032Speter** 10138032Speter** getrequests(e) 10238032Speter** Opens a port and initiates a connection. 10338032Speter** Returns in a child. Must set InChannel and 10438032Speter** OutChannel appropriately. 10538032Speter** clrdaemon() 10638032Speter** Close any open files associated with getting 10738032Speter** the connection; this is used when running the queue, 10838032Speter** etc., to avoid having extra file descriptors during 10938032Speter** the queue run and to avoid confusing the network 11038032Speter** code (if it cares). 11190792Sgshapiro** makeconnection(host, port, mci, e, enough) 11238032Speter** Make a connection to the named host on the given 11390792Sgshapiro** port. Returns zero on success, else an exit status 11490792Sgshapiro** describing the error. 11538032Speter** host_map_lookup(map, hbuf, avp, pstat) 11638032Speter** Convert the entry in hbuf into a canonical form. 11738032Speter*/ 11864562Sgshapiro 11964562Sgshapirostatic DAEMON_T Daemons[MAXDAEMONS]; 12090792Sgshapirostatic int NDaemons = 0; /* actual number of daemons */ 12164562Sgshapiro 12290792Sgshapirostatic time_t NextDiskSpaceCheck = 0; 12364562Sgshapiro 12490792Sgshapiro/* 12538032Speter** GETREQUESTS -- open mail IPC port and get requests. 12638032Speter** 12738032Speter** Parameters: 12838032Speter** e -- the current envelope. 12938032Speter** 13038032Speter** Returns: 13164562Sgshapiro** pointer to flags. 13238032Speter** 13338032Speter** Side Effects: 13438032Speter** Waits until some interesting activity occurs. When 13538032Speter** it does, a child is created to process it, and the 13638032Speter** parent waits for completion. Return from this 13738032Speter** routine is always in the child. The file pointers 13838032Speter** "InChannel" and "OutChannel" should be set to point 13938032Speter** to the communication channel. 14090792Sgshapiro** May restart persistent queue runners if they have ended 14190792Sgshapiro** for some reason. 14238032Speter*/ 14338032Speter 14464562SgshapiroBITMAP256 * 14538032Spetergetrequests(e) 14638032Speter ENVELOPE *e; 14738032Speter{ 14838032Speter int t; 14964562Sgshapiro int idx, curdaemon = -1; 15064562Sgshapiro int i, olddaemon = 0; 15190792Sgshapiro#if XDEBUG 15238032Speter bool j_has_dot; 15390792Sgshapiro#endif /* XDEBUG */ 15442575Speter char status[MAXLINE]; 15564562Sgshapiro SOCKADDR sa; 15664562Sgshapiro SOCKADDR_LEN_T len = sizeof sa; 15794334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 15894334Sgshapiro time_t lastrun; 15994334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 16064562Sgshapiro# if NETUNIX 16142575Speter extern int ControlSocket; 16264562Sgshapiro# endif /* NETUNIX */ 16364562Sgshapiro extern ENVELOPE BlankEnvelope; 16490792Sgshapiro extern bool refuseconnections __P((char *, ENVELOPE *, int, bool)); 16538032Speter 16638032Speter 16790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 16838032Speter { 16964562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 17090792Sgshapiro Daemons[idx].d_firsttime = true; 17164562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 17238032Speter } 17371345Sgshapiro 17438032Speter /* 17538032Speter ** Try to actually open the connection. 17638032Speter */ 17738032Speter 17838032Speter if (tTd(15, 1)) 17964562Sgshapiro { 18090792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 18171345Sgshapiro { 18290792Sgshapiro sm_dprintf("getrequests: daemon %s: port %d\n", 18390792Sgshapiro Daemons[idx].d_name, 18490792Sgshapiro ntohs(Daemons[idx].d_port)); 18571345Sgshapiro } 18664562Sgshapiro } 18738032Speter 18838032Speter /* get a socket for the SMTP connection */ 18990792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 19090792Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true); 19138032Speter 19242575Speter if (opencontrolsocket() < 0) 19342575Speter sm_syslog(LOG_WARNING, NOQID, 19443730Speter "daemon could not open control socket %s: %s", 19590792Sgshapiro ControlSocketName, sm_errstring(errno)); 19642575Speter 19790792Sgshapiro /* If there are any queue runners released reapchild() co-ord's */ 19890792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 19938032Speter 20090792Sgshapiro /* write the pid to file, command line args to syslog */ 20164562Sgshapiro log_sendmail_pid(e); 20238032Speter 20390792Sgshapiro#if XDEBUG 20438032Speter { 20538032Speter char jbuf[MAXHOSTNAMELEN]; 20638032Speter 20738032Speter expand("\201j", jbuf, sizeof jbuf, e); 20838032Speter j_has_dot = strchr(jbuf, '.') != NULL; 20938032Speter } 21090792Sgshapiro#endif /* XDEBUG */ 21138032Speter 21242575Speter /* Add parent process as first item */ 21390792Sgshapiro proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1); 21442575Speter 21538032Speter if (tTd(15, 1)) 21664562Sgshapiro { 21790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 21890792Sgshapiro sm_dprintf("getrequests: daemon %s: %d\n", 21964562Sgshapiro Daemons[idx].d_name, 22064562Sgshapiro Daemons[idx].d_socket); 22164562Sgshapiro } 22238032Speter 22338032Speter for (;;) 22438032Speter { 22538032Speter register pid_t pid; 22638032Speter auto SOCKADDR_LEN_T lotherend; 22790792Sgshapiro bool timedout = false; 22890792Sgshapiro bool control = false; 22964562Sgshapiro int save_errno; 23038032Speter int pipefd[2]; 23190792Sgshapiro time_t now; 23290792Sgshapiro#if STARTTLS 23366494Sgshapiro long seed; 23490792Sgshapiro#endif /* STARTTLS */ 23538032Speter 23638032Speter /* see if we are rejecting connections */ 23790792Sgshapiro (void) sm_blocksignal(SIGALRM); 238120256Sgshapiro CHECK_RESTART; 23964562Sgshapiro 24090792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 24171345Sgshapiro { 24290792Sgshapiro /* 24390792Sgshapiro ** XXX do this call outside the loop? 24490792Sgshapiro ** no: refuse_connections may sleep(). 24590792Sgshapiro */ 24671345Sgshapiro 24790792Sgshapiro now = curtime(); 24890792Sgshapiro if (now < Daemons[idx].d_refuse_connections_until) 24964562Sgshapiro continue; 25090792Sgshapiro if (bitnset(D_DISABLE, Daemons[idx].d_flags)) 25190792Sgshapiro continue; 25290792Sgshapiro if (refuseconnections(Daemons[idx].d_name, e, idx, 25390792Sgshapiro curdaemon == idx)) 25438032Speter { 25564562Sgshapiro if (Daemons[idx].d_socket >= 0) 25642575Speter { 25771345Sgshapiro /* close socket so peer fails quickly */ 25871345Sgshapiro (void) close(Daemons[idx].d_socket); 25971345Sgshapiro Daemons[idx].d_socket = -1; 26042575Speter } 26142575Speter 26242575Speter /* refuse connections for next 15 seconds */ 26390792Sgshapiro Daemons[idx].d_refuse_connections_until = now + 15; 26438032Speter } 26564562Sgshapiro else if (Daemons[idx].d_socket < 0 || 26664562Sgshapiro Daemons[idx].d_firsttime) 26742575Speter { 26890792Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel > 8) 26971345Sgshapiro sm_syslog(LOG_INFO, NOQID, 27071345Sgshapiro "accepting connections again for daemon %s", 27171345Sgshapiro Daemons[idx].d_name); 27264562Sgshapiro 27371345Sgshapiro /* arrange to (re)open the socket if needed */ 27490792Sgshapiro (void) opendaemonsocket(&Daemons[idx], false); 27590792Sgshapiro Daemons[idx].d_firsttime = false; 27642575Speter } 27738032Speter } 27838032Speter 27977349Sgshapiro /* May have been sleeping above, check again */ 280120256Sgshapiro CHECK_RESTART; 28190792Sgshapiro getrequests_checkdiskspace(e); 28271345Sgshapiro 28390792Sgshapiro#if XDEBUG 28438032Speter /* check for disaster */ 28538032Speter { 28638032Speter char jbuf[MAXHOSTNAMELEN]; 28738032Speter 28838032Speter expand("\201j", jbuf, sizeof jbuf, e); 28938032Speter if (!wordinclass(jbuf, 'w')) 29038032Speter { 29138032Speter dumpstate("daemon lost $j"); 29238032Speter sm_syslog(LOG_ALERT, NOQID, 29364562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 29438032Speter abort(); 29538032Speter } 29638032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 29738032Speter { 29838032Speter dumpstate("daemon $j lost dot"); 29938032Speter sm_syslog(LOG_ALERT, NOQID, 30064562Sgshapiro "daemon process $j lost dot; see syslog"); 30138032Speter abort(); 30238032Speter } 30338032Speter } 30490792Sgshapiro#endif /* XDEBUG */ 30538032Speter 30690792Sgshapiro#if 0 30738032Speter /* 30838032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 30938032Speter ** fix the SVr4 problem. But it seems to have gone away, 31038032Speter ** so is it worth doing this? 31138032Speter */ 31238032Speter 31342575Speter if (DaemonSocket >= 0 && 31490792Sgshapiro SetNonBlocking(DaemonSocket, false) < 0) 31538032Speter log an error here; 31690792Sgshapiro#endif /* 0 */ 31790792Sgshapiro (void) sm_releasesignal(SIGALRM); 31864562Sgshapiro 31938032Speter for (;;) 32038032Speter { 32190792Sgshapiro bool setproc = false; 32242575Speter int highest = -1; 32338032Speter fd_set readfds; 32438032Speter struct timeval timeout; 32538032Speter 326120256Sgshapiro CHECK_RESTART; 32738032Speter FD_ZERO(&readfds); 32890792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 32942575Speter { 33064562Sgshapiro /* wait for a connection */ 33164562Sgshapiro if (Daemons[idx].d_socket >= 0) 33264562Sgshapiro { 33371345Sgshapiro if (!setproc && 33471345Sgshapiro !bitnset(D_ETRNONLY, 33571345Sgshapiro Daemons[idx].d_flags)) 33664562Sgshapiro { 33790792Sgshapiro sm_setproctitle(true, e, 33864562Sgshapiro "accepting connections"); 33990792Sgshapiro setproc = true; 34064562Sgshapiro } 34164562Sgshapiro if (Daemons[idx].d_socket > highest) 34264562Sgshapiro highest = Daemons[idx].d_socket; 34390792Sgshapiro SM_FD_SET(Daemons[idx].d_socket, 34490792Sgshapiro &readfds); 34564562Sgshapiro } 34642575Speter } 34764562Sgshapiro 34890792Sgshapiro#if NETUNIX 34942575Speter if (ControlSocket >= 0) 35042575Speter { 35142575Speter if (ControlSocket > highest) 35242575Speter highest = ControlSocket; 35390792Sgshapiro SM_FD_SET(ControlSocket, &readfds); 35442575Speter } 35590792Sgshapiro#endif /* NETUNIX */ 35664562Sgshapiro 35777349Sgshapiro timeout.tv_sec = 5; 35838032Speter timeout.tv_usec = 0; 35938032Speter 36042575Speter t = select(highest + 1, FDSET_CAST &readfds, 36164562Sgshapiro NULL, NULL, &timeout); 36242575Speter 36377349Sgshapiro /* Did someone signal while waiting? */ 364120256Sgshapiro CHECK_RESTART; 36571345Sgshapiro 36671345Sgshapiro 36790792Sgshapiro curdaemon = -1; 36890792Sgshapiro if (doqueuerun()) 36994334Sgshapiro { 37090792Sgshapiro (void) runqueue(true, false, false, false); 37194334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 37294334Sgshapiro lastrun = now; 37394334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 37494334Sgshapiro } 37594334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 37694334Sgshapiro else if (QueueIntvl > 0 && 37794334Sgshapiro lastrun + QueueIntvl + 60 < now) 37894334Sgshapiro { 37971345Sgshapiro 38094334Sgshapiro /* 38194334Sgshapiro ** set lastrun unconditionally to avoid 38294334Sgshapiro ** calling checkqueuerunner() all the time. 38394334Sgshapiro ** That's also why we currently ignore the 38494334Sgshapiro ** result of the function call. 38594334Sgshapiro */ 38694334Sgshapiro 38794334Sgshapiro (void) checkqueuerunner(); 38894334Sgshapiro lastrun = now; 38994334Sgshapiro } 39094334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 39194334Sgshapiro 39242575Speter if (t <= 0) 39342575Speter { 39490792Sgshapiro timedout = true; 39542575Speter break; 39642575Speter } 39738032Speter 39890792Sgshapiro control = false; 39938032Speter errno = 0; 40064562Sgshapiro 40164562Sgshapiro /* look "round-robin" for an active socket */ 40290792Sgshapiro if ((idx = olddaemon + 1) >= NDaemons) 40364562Sgshapiro idx = 0; 40490792Sgshapiro for (i = 0; i < NDaemons; i++) 40542575Speter { 40664562Sgshapiro if (Daemons[idx].d_socket >= 0 && 40790792Sgshapiro SM_FD_ISSET(Daemons[idx].d_socket, 40890792Sgshapiro &readfds)) 40964562Sgshapiro { 41064562Sgshapiro lotherend = Daemons[idx].d_socksize; 41173188Sgshapiro memset(&RealHostAddr, '\0', 41273188Sgshapiro sizeof RealHostAddr); 41364562Sgshapiro t = accept(Daemons[idx].d_socket, 41464562Sgshapiro (struct sockaddr *)&RealHostAddr, 41564562Sgshapiro &lotherend); 41673188Sgshapiro 41773188Sgshapiro /* 41873188Sgshapiro ** If remote side closes before 41973188Sgshapiro ** accept() finishes, sockaddr 42073188Sgshapiro ** might not be fully filled in. 42173188Sgshapiro */ 42273188Sgshapiro 42373188Sgshapiro if (t >= 0 && 42473188Sgshapiro (lotherend == 0 || 42573188Sgshapiro# ifdef BSD4_4_SOCKADDR 42673188Sgshapiro RealHostAddr.sa.sa_len == 0 || 42773188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 42873188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 42973188Sgshapiro { 43073188Sgshapiro (void) close(t); 43173188Sgshapiro t = -1; 43273188Sgshapiro errno = EINVAL; 43373188Sgshapiro } 43464562Sgshapiro olddaemon = curdaemon = idx; 43564562Sgshapiro break; 43664562Sgshapiro } 43790792Sgshapiro if (++idx >= NDaemons) 43864562Sgshapiro idx = 0; 43942575Speter } 44090792Sgshapiro#if NETUNIX 44164562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 44290792Sgshapiro SM_FD_ISSET(ControlSocket, &readfds)) 44342575Speter { 44442575Speter struct sockaddr_un sa_un; 44542575Speter 44642575Speter lotherend = sizeof sa_un; 44773188Sgshapiro memset(&sa_un, '\0', sizeof sa_un); 44842575Speter t = accept(ControlSocket, 44942575Speter (struct sockaddr *)&sa_un, 45042575Speter &lotherend); 45173188Sgshapiro 45273188Sgshapiro /* 45373188Sgshapiro ** If remote side closes before 45473188Sgshapiro ** accept() finishes, sockaddr 45573188Sgshapiro ** might not be fully filled in. 45673188Sgshapiro */ 45773188Sgshapiro 45873188Sgshapiro if (t >= 0 && 45973188Sgshapiro (lotherend == 0 || 46073188Sgshapiro# ifdef BSD4_4_SOCKADDR 46173188Sgshapiro sa_un.sun_len == 0 || 46273188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 46373188Sgshapiro sa_un.sun_family != AF_UNIX)) 46473188Sgshapiro { 46573188Sgshapiro (void) close(t); 46673188Sgshapiro t = -1; 46773188Sgshapiro errno = EINVAL; 46873188Sgshapiro } 46973188Sgshapiro if (t >= 0) 47090792Sgshapiro control = true; 47142575Speter } 47290792Sgshapiro#else /* NETUNIX */ 47371345Sgshapiro if (curdaemon == -1) 47471345Sgshapiro { 47571345Sgshapiro /* No daemon to service */ 47671345Sgshapiro continue; 47771345Sgshapiro } 47890792Sgshapiro#endif /* NETUNIX */ 47938032Speter if (t >= 0 || errno != EINTR) 48038032Speter break; 48138032Speter } 48242575Speter if (timedout) 48342575Speter { 48490792Sgshapiro timedout = false; 48542575Speter continue; 48642575Speter } 48764562Sgshapiro save_errno = errno; 48890792Sgshapiro (void) sm_blocksignal(SIGALRM); 48938032Speter if (t < 0) 49038032Speter { 49164562Sgshapiro errno = save_errno; 49238032Speter syserr("getrequests: accept"); 49338032Speter 49438032Speter /* arrange to re-open the socket next time around */ 49564562Sgshapiro (void) close(Daemons[curdaemon].d_socket); 49664562Sgshapiro Daemons[curdaemon].d_socket = -1; 49790792Sgshapiro#if SO_REUSEADDR_IS_BROKEN 49864562Sgshapiro /* 49964562Sgshapiro ** Give time for bound socket to be released. 50064562Sgshapiro ** This creates a denial-of-service if you can 50164562Sgshapiro ** force accept() to fail on affected systems. 50264562Sgshapiro */ 50364562Sgshapiro 50490792Sgshapiro Daemons[curdaemon].d_refuse_connections_until = curtime() + 15; 50590792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */ 50638032Speter continue; 50738032Speter } 50838032Speter 50964562Sgshapiro if (!control) 51064562Sgshapiro { 51164562Sgshapiro /* set some daemon related macros */ 51264562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 51364562Sgshapiro { 51464562Sgshapiro case AF_UNSPEC: 51590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 51690792Sgshapiro macid("{daemon_family}"), "unspec"); 51764562Sgshapiro break; 51890792Sgshapiro#if _FFR_DAEMON_NETUNIX 51990792Sgshapiro# if NETUNIX 52090792Sgshapiro case AF_UNIX: 52190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 52290792Sgshapiro macid("{daemon_family}"), "local"); 52390792Sgshapiro break; 52490792Sgshapiro# endif /* NETUNIX */ 52590792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 52690792Sgshapiro#if NETINET 52764562Sgshapiro case AF_INET: 52890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 52990792Sgshapiro macid("{daemon_family}"), "inet"); 53064562Sgshapiro break; 53190792Sgshapiro#endif /* NETINET */ 53290792Sgshapiro#if NETINET6 53364562Sgshapiro case AF_INET6: 53490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53590792Sgshapiro macid("{daemon_family}"), "inet6"); 53664562Sgshapiro break; 53790792Sgshapiro#endif /* NETINET6 */ 53890792Sgshapiro#if NETISO 53964562Sgshapiro case AF_ISO: 54090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54190792Sgshapiro macid("{daemon_family}"), "iso"); 54264562Sgshapiro break; 54390792Sgshapiro#endif /* NETISO */ 54490792Sgshapiro#if NETNS 54564562Sgshapiro case AF_NS: 54690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54790792Sgshapiro macid("{daemon_family}"), "ns"); 54864562Sgshapiro break; 54990792Sgshapiro#endif /* NETNS */ 55090792Sgshapiro#if NETX25 55164562Sgshapiro case AF_CCITT: 55290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55390792Sgshapiro macid("{daemon_family}"), "x.25"); 55464562Sgshapiro break; 55590792Sgshapiro#endif /* NETX25 */ 55664562Sgshapiro } 55790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55890792Sgshapiro macid("{daemon_name}"), 55990792Sgshapiro Daemons[curdaemon].d_name); 56064562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 56190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56290792Sgshapiro macid("{daemon_flags}"), 56390792Sgshapiro Daemons[curdaemon].d_mflags); 56464562Sgshapiro else 56590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56690792Sgshapiro macid("{daemon_flags}"), ""); 56764562Sgshapiro } 56864562Sgshapiro 56938032Speter /* 57038032Speter ** Create a subprocess to process the mail. 57138032Speter */ 57238032Speter 57338032Speter if (tTd(15, 2)) 57490792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 57538032Speter 57638032Speter /* 57790792Sgshapiro ** Advance state of PRNG. 57890792Sgshapiro ** This is necessary because otherwise all child processes 57964562Sgshapiro ** will produce the same PRN sequence and hence the selection 58064562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 58164562Sgshapiro ** are not "really" random. 58264562Sgshapiro */ 58390792Sgshapiro#if STARTTLS 58490792Sgshapiro /* XXX get some better "random" data? */ 58566494Sgshapiro seed = get_random(); 58690792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 58790792Sgshapiro sizeof NextDiskSpaceCheck); 58890792Sgshapiro RAND_seed((void *) &now, sizeof now); 58966494Sgshapiro RAND_seed((void *) &seed, sizeof seed); 59090792Sgshapiro#else /* STARTTLS */ 59164562Sgshapiro (void) get_random(); 59290792Sgshapiro#endif /* STARTTLS */ 59364562Sgshapiro 59490792Sgshapiro#if NAMED_BIND 59564562Sgshapiro /* 59690792Sgshapiro ** Update MX records for FallBackMX. 59790792Sgshapiro ** Let's hope this is fast otherwise we screw up the 59890792Sgshapiro ** response time. 59990792Sgshapiro */ 60090792Sgshapiro 60190792Sgshapiro if (FallBackMX != NULL) 60290792Sgshapiro (void) getfallbackmxrr(FallBackMX); 60390792Sgshapiro#endif /* NAMED_BIND */ 60490792Sgshapiro 605110560Sgshapiro if (tTd(93, 100)) 606110560Sgshapiro { 607110560Sgshapiro /* don't fork, handle connection in this process */ 608110560Sgshapiro pid = 0; 60938032Speter pipefd[0] = pipefd[1] = -1; 610110560Sgshapiro } 611110560Sgshapiro else 612110560Sgshapiro { 613110560Sgshapiro /* 614110560Sgshapiro ** Create a pipe to keep the child from writing to 615110560Sgshapiro ** the socket until after the parent has closed 616110560Sgshapiro ** it. Otherwise the parent may hang if the child 617110560Sgshapiro ** has closed it first. 618110560Sgshapiro */ 61938032Speter 620110560Sgshapiro if (pipe(pipefd) < 0) 621110560Sgshapiro pipefd[0] = pipefd[1] = -1; 622110560Sgshapiro 623110560Sgshapiro (void) sm_blocksignal(SIGCHLD); 624110560Sgshapiro pid = fork(); 625110560Sgshapiro if (pid < 0) 62638032Speter { 627110560Sgshapiro syserr("daemon: cannot fork"); 628110560Sgshapiro if (pipefd[0] != -1) 629110560Sgshapiro { 630110560Sgshapiro (void) close(pipefd[0]); 631110560Sgshapiro (void) close(pipefd[1]); 632110560Sgshapiro } 633110560Sgshapiro (void) sm_releasesignal(SIGCHLD); 634110560Sgshapiro (void) sleep(10); 635110560Sgshapiro (void) close(t); 636110560Sgshapiro continue; 63738032Speter } 63838032Speter } 63990792Sgshapiro 64038032Speter if (pid == 0) 64138032Speter { 64238032Speter char *p; 64390792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 64438032Speter 64538032Speter /* 64638032Speter ** CHILD -- return to caller. 64738032Speter ** Collect verified idea of sending host. 64838032Speter ** Verify calling user id if possible here. 64938032Speter */ 65038032Speter 65177349Sgshapiro /* Reset global flags */ 65277349Sgshapiro RestartRequest = NULL; 65390792Sgshapiro RestartWorkGroup = false; 65477349Sgshapiro ShutdownRequest = NULL; 65577349Sgshapiro PendingSignal = 0; 65690792Sgshapiro CurrentPid = getpid(); 65777349Sgshapiro 65890792Sgshapiro (void) sm_releasesignal(SIGALRM); 65990792Sgshapiro (void) sm_releasesignal(SIGCHLD); 66090792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 66190792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 66290792Sgshapiro (void) sm_signal(SIGTERM, intsig); 66377349Sgshapiro 66490792Sgshapiro /* turn on profiling */ 66590792Sgshapiro /* SM_PROF(0); */ 66690792Sgshapiro 66790792Sgshapiro /* 66890792Sgshapiro ** Initialize exception stack and default exception 66990792Sgshapiro ** handler for child process. 67090792Sgshapiro */ 67190792Sgshapiro 67290792Sgshapiro sm_exc_newthread(fatal_error); 67390792Sgshapiro 67464562Sgshapiro if (!control) 67564562Sgshapiro { 67690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 67790792Sgshapiro macid("{daemon_addr}"), 67890792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 67990792Sgshapiro (void) sm_snprintf(status, sizeof status, "%d", 68064562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 68190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 68290792Sgshapiro macid("{daemon_port}"), status); 68364562Sgshapiro } 68464562Sgshapiro 68590792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 68664562Sgshapiro { 68764562Sgshapiro if (Daemons[idx].d_socket >= 0) 68864562Sgshapiro (void) close(Daemons[idx].d_socket); 68980785Sgshapiro Daemons[idx].d_socket = -1; 69064562Sgshapiro } 69142575Speter clrcontrol(); 69238032Speter 69364562Sgshapiro /* Avoid SMTP daemon actions if control command */ 69464562Sgshapiro if (control) 69564562Sgshapiro { 69664562Sgshapiro /* Add control socket process */ 69790792Sgshapiro proc_list_add(CurrentPid, 69890792Sgshapiro "console socket child", 69990792Sgshapiro PROC_CONTROL_CHILD, 0, -1); 70064562Sgshapiro } 70164562Sgshapiro else 70264562Sgshapiro { 70364562Sgshapiro proc_list_clear(); 70442575Speter 70590792Sgshapiro /* clean up background delivery children */ 70690792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 70790792Sgshapiro 70864562Sgshapiro /* Add parent process as first child item */ 70990792Sgshapiro proc_list_add(CurrentPid, "daemon child", 71090792Sgshapiro PROC_DAEMON_CHILD, 0, -1); 71138032Speter 71264562Sgshapiro /* don't schedule queue runs if ETRN */ 71364562Sgshapiro QueueIntvl = 0; 71438032Speter 71590792Sgshapiro sm_setproctitle(true, e, "startup with %s", 71664562Sgshapiro anynet_ntoa(&RealHostAddr)); 71764562Sgshapiro } 71864562Sgshapiro 71938032Speter if (pipefd[0] != -1) 72038032Speter { 72138032Speter auto char c; 72238032Speter 72338032Speter /* 72438032Speter ** Wait for the parent to close the write end 72538032Speter ** of the pipe, which we will see as an EOF. 72638032Speter ** This guarantees that we won't write to the 72738032Speter ** socket until after the parent has closed 72838032Speter ** the pipe. 72938032Speter */ 73038032Speter 73138032Speter /* close the write end of the pipe */ 73238032Speter (void) close(pipefd[1]); 73338032Speter 73438032Speter /* we shouldn't be interrupted, but ... */ 73538032Speter while (read(pipefd[0], &c, 1) < 0 && 73638032Speter errno == EINTR) 73738032Speter continue; 73838032Speter (void) close(pipefd[0]); 73938032Speter } 74038032Speter 74164562Sgshapiro /* control socket processing */ 74264562Sgshapiro if (control) 74364562Sgshapiro { 74464562Sgshapiro control_command(t, e); 74564562Sgshapiro /* NOTREACHED */ 74664562Sgshapiro exit(EX_SOFTWARE); 74764562Sgshapiro } 74864562Sgshapiro 74938032Speter /* determine host name */ 75038032Speter p = hostnamebyanyaddr(&RealHostAddr); 75190792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 75238032Speter p[MAXNAME] = '\0'; 75338032Speter RealHostName = newstr(p); 75464562Sgshapiro if (RealHostName[0] == '[') 75564562Sgshapiro { 75690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 75790792Sgshapiro macid("{client_resolve}"), 75890792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 75964562Sgshapiro } 76064562Sgshapiro else 76190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 76290792Sgshapiro macid("{client_resolve}"), "OK"); 76390792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 76494334Sgshapiro markstats(e, NULL, STATS_CONNECT); 76538032Speter 76690792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 76790792Sgshapiro SM_TIME_DEFAULT, 76890792Sgshapiro (void *) &t, 76990792Sgshapiro SM_IO_RDONLY, 77090792Sgshapiro NULL)) == NULL || 77138032Speter (t = dup(t)) < 0 || 77290792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 77390792Sgshapiro SM_TIME_DEFAULT, 77490792Sgshapiro (void *) &t, 77590792Sgshapiro SM_IO_WRONLY, 77690792Sgshapiro NULL)) == NULL) 77738032Speter { 77890792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 77990792Sgshapiro t); 78090792Sgshapiro finis(false, true, EX_OK); 78138032Speter } 78290792Sgshapiro sm_io_automode(inchannel, outchannel); 78338032Speter 78438032Speter InChannel = inchannel; 78538032Speter OutChannel = outchannel; 78690792Sgshapiro DisConnected = false; 78738032Speter 78890792Sgshapiro#if XLA 78938032Speter if (!xla_host_ok(RealHostName)) 79038032Speter { 79164562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 79290792Sgshapiro finis(false, true, EX_OK); 79338032Speter } 79490792Sgshapiro#endif /* XLA */ 79564562Sgshapiro /* find out name for interface of connection */ 79690792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 79790792Sgshapiro NULL), &sa.sa, &len) == 0) 79864562Sgshapiro { 79964562Sgshapiro p = hostnamebyanyaddr(&sa); 80064562Sgshapiro if (tTd(15, 9)) 80190792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 80290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 80390792Sgshapiro macid("{if_name}"), p); 80464562Sgshapiro 80590792Sgshapiro /* 80690792Sgshapiro ** Do this only if it is not the loopback 80790792Sgshapiro ** interface. 80890792Sgshapiro */ 80990792Sgshapiro 81064562Sgshapiro if (!isloopback(sa)) 81164562Sgshapiro { 81290792Sgshapiro char *addr; 81390792Sgshapiro char family[5]; 81490792Sgshapiro 81590792Sgshapiro addr = anynet_ntoa(&sa); 81690792Sgshapiro (void) sm_snprintf(family, 81790792Sgshapiro sizeof(family), 81890792Sgshapiro "%d", sa.sa.sa_family); 81990792Sgshapiro macdefine(&BlankEnvelope.e_macro, 82090792Sgshapiro A_TEMP, 82190792Sgshapiro macid("{if_addr}"), addr); 82290792Sgshapiro macdefine(&BlankEnvelope.e_macro, 82390792Sgshapiro A_TEMP, 82490792Sgshapiro macid("{if_family}"), family); 82564562Sgshapiro if (tTd(15, 7)) 82690792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 82790792Sgshapiro addr, family); 82864562Sgshapiro } 82964562Sgshapiro else 83064562Sgshapiro { 83190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 83290792Sgshapiro A_PERM, 83390792Sgshapiro macid("{if_addr}"), NULL); 83490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 83590792Sgshapiro A_PERM, 83690792Sgshapiro macid("{if_family}"), NULL); 83764562Sgshapiro } 83864562Sgshapiro } 83964562Sgshapiro else 84064562Sgshapiro { 84164562Sgshapiro if (tTd(15, 7)) 84290792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 84390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 84490792Sgshapiro macid("{if_name}"), NULL); 84590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 84690792Sgshapiro macid("{if_addr}"), NULL); 84790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 84890792Sgshapiro macid("{if_family}"), NULL); 84964562Sgshapiro } 85038032Speter break; 85138032Speter } 85238032Speter 85338032Speter /* parent -- keep track of children */ 85464562Sgshapiro if (control) 85564562Sgshapiro { 85690792Sgshapiro (void) sm_snprintf(status, sizeof status, 85790792Sgshapiro "control socket server child"); 85890792Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1); 85964562Sgshapiro } 86064562Sgshapiro else 86164562Sgshapiro { 86290792Sgshapiro (void) sm_snprintf(status, sizeof status, 86390792Sgshapiro "SMTP server child for %s", 86490792Sgshapiro anynet_ntoa(&RealHostAddr)); 86590792Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1); 86664562Sgshapiro } 86790792Sgshapiro (void) sm_releasesignal(SIGCHLD); 86838032Speter 86938032Speter /* close the read end of the synchronization pipe */ 87038032Speter if (pipefd[0] != -1) 87164562Sgshapiro { 87238032Speter (void) close(pipefd[0]); 87364562Sgshapiro pipefd[0] = -1; 87464562Sgshapiro } 87538032Speter 87638032Speter /* close the port so that others will hang (for a while) */ 87738032Speter (void) close(t); 87838032Speter 87938032Speter /* release the child by closing the read end of the sync pipe */ 88038032Speter if (pipefd[1] != -1) 88164562Sgshapiro { 88238032Speter (void) close(pipefd[1]); 88364562Sgshapiro pipefd[1] = -1; 88464562Sgshapiro } 88538032Speter } 88690792Sgshapiro if (tTd(15, 2)) 88790792Sgshapiro sm_dprintf("getreq: returning\n"); 88864562Sgshapiro 88990792Sgshapiro#if MILTER 89090792Sgshapiro# if _FFR_MILTER_PERDAEMON 89190792Sgshapiro /* set the filters for this daemon */ 89290792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 89390792Sgshapiro { 89490792Sgshapiro for (i = 0; 895110560Sgshapiro (i < MAXFILTERS && 896110560Sgshapiro Daemons[curdaemon].d_inputfilters[i] != NULL); 89790792Sgshapiro i++) 89890792Sgshapiro { 89990792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 90090792Sgshapiro } 90190792Sgshapiro if (i < MAXFILTERS) 90290792Sgshapiro InputFilters[i] = NULL; 90390792Sgshapiro } 90490792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 90590792Sgshapiro#endif /* MILTER */ 90664562Sgshapiro return &Daemons[curdaemon].d_flags; 90738032Speter} 90890792Sgshapiro 90990792Sgshapiro/* 91090792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 91190792Sgshapiro** 91290792Sgshapiro** Parameters: 91390792Sgshapiro** e -- envelope. 91490792Sgshapiro** 91590792Sgshapiro** Returns: 91690792Sgshapiro** none. 91790792Sgshapiro** 91890792Sgshapiro** Side Effects: 91990792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 92090792Sgshapiro*/ 92190792Sgshapiro 92290792Sgshapirostatic void 92390792Sgshapirogetrequests_checkdiskspace(e) 92490792Sgshapiro ENVELOPE *e; 92590792Sgshapiro{ 92690792Sgshapiro bool logged = false; 92790792Sgshapiro int idx; 92890792Sgshapiro time_t now; 92990792Sgshapiro 93090792Sgshapiro now = curtime(); 93190792Sgshapiro if (now < NextDiskSpaceCheck) 93290792Sgshapiro return; 93390792Sgshapiro 93490792Sgshapiro /* Check if there is available disk space in all queue groups. */ 93590792Sgshapiro if (!enoughdiskspace(0, NULL)) 93690792Sgshapiro { 93790792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 93890792Sgshapiro { 93990792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 94090792Sgshapiro continue; 94190792Sgshapiro 94290792Sgshapiro /* log only if not logged before */ 94390792Sgshapiro if (!logged) 94490792Sgshapiro { 94590792Sgshapiro if (LogLevel > 8) 94690792Sgshapiro sm_syslog(LOG_INFO, NOQID, 94790792Sgshapiro "rejecting new messages: min free: %ld", 94890792Sgshapiro MinBlocksFree); 94990792Sgshapiro sm_setproctitle(true, e, 95090792Sgshapiro "rejecting new messages: min free: %ld", 95190792Sgshapiro MinBlocksFree); 95290792Sgshapiro logged = true; 95390792Sgshapiro } 95490792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 95590792Sgshapiro } 95690792Sgshapiro } 95790792Sgshapiro else 95890792Sgshapiro { 95990792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 96090792Sgshapiro { 96190792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 96290792Sgshapiro continue; 96390792Sgshapiro 96490792Sgshapiro /* log only if not logged before */ 96590792Sgshapiro if (!logged) 96690792Sgshapiro { 96790792Sgshapiro if (LogLevel > 8) 96890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 96990792Sgshapiro "accepting new messages (again)"); 97090792Sgshapiro logged = true; 97190792Sgshapiro } 97290792Sgshapiro 97390792Sgshapiro /* title will be set later */ 97490792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 97590792Sgshapiro } 97690792Sgshapiro } 97790792Sgshapiro 97890792Sgshapiro /* only check disk space once a minute */ 97990792Sgshapiro NextDiskSpaceCheck = now + 60; 98090792Sgshapiro} 98190792Sgshapiro 98290792Sgshapiro/* 98364562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 98438032Speter** 98564562Sgshapiro** Deals with setting all appropriate options. 98638032Speter** 98738032Speter** Parameters: 98864562Sgshapiro** d -- the structure for the daemon to open. 98938032Speter** firsttime -- set if this is the initial open. 99038032Speter** 99138032Speter** Returns: 99238032Speter** Size in bytes of the daemon socket addr. 99338032Speter** 99438032Speter** Side Effects: 99538032Speter** Leaves DaemonSocket set to the open socket. 99638032Speter** Exits if the socket cannot be created. 99738032Speter*/ 99838032Speter 99990792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 100038032Speter 100164562Sgshapirostatic int 100264562Sgshapiroopendaemonsocket(d, firsttime) 100390792Sgshapiro DAEMON_T *d; 100438032Speter bool firsttime; 100538032Speter{ 100638032Speter int on = 1; 100764562Sgshapiro int fdflags; 100864562Sgshapiro SOCKADDR_LEN_T socksize = 0; 100938032Speter int ntries = 0; 101064562Sgshapiro int save_errno; 101138032Speter 101238032Speter if (tTd(15, 2)) 101390792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 101438032Speter 101538032Speter do 101638032Speter { 101738032Speter if (ntries > 0) 101864562Sgshapiro (void) sleep(5); 101964562Sgshapiro if (firsttime || d->d_socket < 0) 102038032Speter { 102190792Sgshapiro#if _FFR_DAEMON_NETUNIX 102290792Sgshapiro# if NETUNIX 102390792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 102490792Sgshapiro { 102590792Sgshapiro int rval; 102690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 102790792Sgshapiro 102890792Sgshapiro /* if not safe, don't use it */ 102990792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 103090792Sgshapiro RunAsUid, RunAsGid, 103190792Sgshapiro RunAsUserName, sff, 103290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 103390792Sgshapiro if (rval != 0) 103490792Sgshapiro { 103590792Sgshapiro save_errno = errno; 103690792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 103790792Sgshapiro d->d_name, 103890792Sgshapiro d->d_addr.sunix.sun_path); 103990792Sgshapiro goto fail; 104090792Sgshapiro } 104190792Sgshapiro 104290792Sgshapiro /* Don't try to overtake an existing socket */ 104390792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 104490792Sgshapiro } 104590792Sgshapiro# endif /* NETUNIX */ 104690792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */ 104764562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 104864562Sgshapiro SOCK_STREAM, 0); 104964562Sgshapiro if (d->d_socket < 0) 105038032Speter { 105164562Sgshapiro save_errno = errno; 105290792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 105390792Sgshapiro d->d_name); 105490792Sgshapiro fail: 105590792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 105690792Sgshapiro (!transienterror(save_errno) || 105790792Sgshapiro ntries >= MAXOPENTRIES - 1)) 105890792Sgshapiro { 105990792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 106090792Sgshapiro d->d_name); 106190792Sgshapiro setbitn(D_DISABLE, d->d_flags); 106290792Sgshapiro d->d_socket = -1; 106390792Sgshapiro return -1; 106490792Sgshapiro } 106538032Speter severe: 106638032Speter if (LogLevel > 0) 106738032Speter sm_syslog(LOG_ALERT, NOQID, 106890792Sgshapiro "daemon %s: problem creating SMTP socket", 106990792Sgshapiro d->d_name); 107064562Sgshapiro d->d_socket = -1; 107138032Speter continue; 107238032Speter } 107338032Speter 1074110560Sgshapiro if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE) 1075110560Sgshapiro { 1076110560Sgshapiro save_errno = EINVAL; 1077110560Sgshapiro syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", 1078110560Sgshapiro d->d_name, d->d_socket); 1079110560Sgshapiro goto fail; 1080110560Sgshapiro } 1081110560Sgshapiro 108238032Speter /* turn on network debugging? */ 108338032Speter if (tTd(15, 101)) 108464562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 108538032Speter SO_DEBUG, (char *)&on, 108638032Speter sizeof on); 108738032Speter 108864562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 108938032Speter SO_REUSEADDR, (char *)&on, sizeof on); 109064562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 109138032Speter SO_KEEPALIVE, (char *)&on, sizeof on); 109238032Speter 109390792Sgshapiro#ifdef SO_RCVBUF 109464562Sgshapiro if (d->d_tcprcvbufsize > 0) 109538032Speter { 109664562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 109738032Speter SO_RCVBUF, 109864562Sgshapiro (char *) &d->d_tcprcvbufsize, 109964562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 110064562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 110138032Speter } 110290792Sgshapiro#endif /* SO_RCVBUF */ 110390792Sgshapiro#ifdef SO_SNDBUF 110464562Sgshapiro if (d->d_tcpsndbufsize > 0) 110564562Sgshapiro { 110664562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 110764562Sgshapiro SO_SNDBUF, 110864562Sgshapiro (char *) &d->d_tcpsndbufsize, 110964562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 111064562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 111164562Sgshapiro } 111290792Sgshapiro#endif /* SO_SNDBUF */ 111338032Speter 111464562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 111564562Sgshapiro fcntl(d->d_socket, F_SETFD, 111664562Sgshapiro fdflags | FD_CLOEXEC) == -1) 111738032Speter { 111864562Sgshapiro save_errno = errno; 111964562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 112064562Sgshapiro d->d_name, 112164562Sgshapiro fdflags == -1 ? "get" : "set", 112290792Sgshapiro sm_errstring(save_errno)); 112364562Sgshapiro (void) close(d->d_socket); 112464562Sgshapiro goto severe; 112564562Sgshapiro } 112664562Sgshapiro 112764562Sgshapiro switch (d->d_addr.sa.sa_family) 112864562Sgshapiro { 112990792Sgshapiro#if _FFR_DAEMON_NETUNIX 113090792Sgshapiro# ifdef NETUNIX 113190792Sgshapiro case AF_UNIX: 113290792Sgshapiro socksize = sizeof d->d_addr.sunix; 113390792Sgshapiro break; 113490792Sgshapiro# endif /* NETUNIX */ 113590792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 113690792Sgshapiro#if NETINET 113738032Speter case AF_INET: 113864562Sgshapiro socksize = sizeof d->d_addr.sin; 113938032Speter break; 114090792Sgshapiro#endif /* NETINET */ 114138032Speter 114290792Sgshapiro#if NETINET6 114364562Sgshapiro case AF_INET6: 114464562Sgshapiro socksize = sizeof d->d_addr.sin6; 114564562Sgshapiro break; 114690792Sgshapiro#endif /* NETINET6 */ 114764562Sgshapiro 114890792Sgshapiro#if NETISO 114938032Speter case AF_ISO: 115064562Sgshapiro socksize = sizeof d->d_addr.siso; 115138032Speter break; 115290792Sgshapiro#endif /* NETISO */ 115338032Speter 115438032Speter default: 115564562Sgshapiro socksize = sizeof d->d_addr; 115638032Speter break; 115738032Speter } 115838032Speter 115964562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 116038032Speter { 116138032Speter /* probably another daemon already */ 116264562Sgshapiro save_errno = errno; 116364562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 116464562Sgshapiro d->d_name); 116564562Sgshapiro (void) close(d->d_socket); 116690792Sgshapiro goto fail; 116738032Speter } 116838032Speter } 116964562Sgshapiro if (!firsttime && 117064562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 117138032Speter { 117264562Sgshapiro save_errno = errno; 117364562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 117464562Sgshapiro d->d_name); 117564562Sgshapiro (void) close(d->d_socket); 117638032Speter goto severe; 117738032Speter } 117838032Speter return socksize; 117964562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 118064562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 118164562Sgshapiro d->d_name); 118264562Sgshapiro /* NOTREACHED */ 118338032Speter return -1; /* avoid compiler warning on IRIX */ 118438032Speter} 118590792Sgshapiro/* 118664562Sgshapiro** SETUPDAEMON -- setup socket for daemon 118764562Sgshapiro** 118864562Sgshapiro** Parameters: 118964562Sgshapiro** daemonaddr -- socket for daemon 119064562Sgshapiro** 119164562Sgshapiro** Returns: 119264562Sgshapiro** port number on which daemon should run 119364562Sgshapiro** 119464562Sgshapiro*/ 119590792Sgshapiro 119690792Sgshapirostatic unsigned short 119764562Sgshapirosetupdaemon(daemonaddr) 119864562Sgshapiro SOCKADDR *daemonaddr; 119964562Sgshapiro{ 120090792Sgshapiro unsigned short port; 120164562Sgshapiro 120264562Sgshapiro /* 120364562Sgshapiro ** Set up the address for the mailer. 120464562Sgshapiro */ 120564562Sgshapiro 120664562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 120764562Sgshapiro { 120864562Sgshapiro memset(daemonaddr, '\0', sizeof *daemonaddr); 120990792Sgshapiro#if NETINET 121064562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 121190792Sgshapiro#endif /* NETINET */ 121264562Sgshapiro } 121364562Sgshapiro 121464562Sgshapiro switch (daemonaddr->sa.sa_family) 121564562Sgshapiro { 121690792Sgshapiro#if NETINET 121764562Sgshapiro case AF_INET: 121864562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 121964562Sgshapiro daemonaddr->sin.sin_addr.s_addr = INADDR_ANY; 122064562Sgshapiro port = daemonaddr->sin.sin_port; 122164562Sgshapiro break; 122290792Sgshapiro#endif /* NETINET */ 122364562Sgshapiro 122490792Sgshapiro#if NETINET6 122564562Sgshapiro case AF_INET6: 122664562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 122764562Sgshapiro daemonaddr->sin6.sin6_addr = in6addr_any; 122864562Sgshapiro port = daemonaddr->sin6.sin6_port; 122964562Sgshapiro break; 123090792Sgshapiro#endif /* NETINET6 */ 123164562Sgshapiro 123264562Sgshapiro default: 123364562Sgshapiro /* unknown protocol */ 123464562Sgshapiro port = 0; 123564562Sgshapiro break; 123664562Sgshapiro } 123764562Sgshapiro if (port == 0) 123864562Sgshapiro { 123990792Sgshapiro#ifdef NO_GETSERVBYNAME 124064562Sgshapiro port = htons(25); 124190792Sgshapiro#else /* NO_GETSERVBYNAME */ 124264562Sgshapiro { 124364562Sgshapiro register struct servent *sp; 124464562Sgshapiro 124564562Sgshapiro sp = getservbyname("smtp", "tcp"); 124664562Sgshapiro if (sp == NULL) 124764562Sgshapiro { 124864562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 124964562Sgshapiro port = htons(25); 125064562Sgshapiro } 125164562Sgshapiro else 125264562Sgshapiro port = sp->s_port; 125364562Sgshapiro } 125490792Sgshapiro#endif /* NO_GETSERVBYNAME */ 125564562Sgshapiro } 125664562Sgshapiro 125764562Sgshapiro switch (daemonaddr->sa.sa_family) 125864562Sgshapiro { 125990792Sgshapiro#if NETINET 126064562Sgshapiro case AF_INET: 126164562Sgshapiro daemonaddr->sin.sin_port = port; 126264562Sgshapiro break; 126390792Sgshapiro#endif /* NETINET */ 126464562Sgshapiro 126590792Sgshapiro#if NETINET6 126664562Sgshapiro case AF_INET6: 126764562Sgshapiro daemonaddr->sin6.sin6_port = port; 126864562Sgshapiro break; 126990792Sgshapiro#endif /* NETINET6 */ 127064562Sgshapiro 127164562Sgshapiro default: 127264562Sgshapiro /* unknown protocol */ 127364562Sgshapiro break; 127464562Sgshapiro } 127590792Sgshapiro return port; 127664562Sgshapiro} 127790792Sgshapiro/* 127838032Speter** CLRDAEMON -- reset the daemon connection 127938032Speter** 128038032Speter** Parameters: 128138032Speter** none. 128238032Speter** 128338032Speter** Returns: 128438032Speter** none. 128538032Speter** 128638032Speter** Side Effects: 128738032Speter** releases any resources used by the passive daemon. 128838032Speter*/ 128938032Speter 129038032Spetervoid 129138032Speterclrdaemon() 129238032Speter{ 129364562Sgshapiro int i; 129464562Sgshapiro 129590792Sgshapiro for (i = 0; i < NDaemons; i++) 129664562Sgshapiro { 129764562Sgshapiro if (Daemons[i].d_socket >= 0) 129864562Sgshapiro (void) close(Daemons[i].d_socket); 129964562Sgshapiro Daemons[i].d_socket = -1; 130064562Sgshapiro } 130138032Speter} 130290792Sgshapiro 130390792Sgshapiro/* 130490792Sgshapiro** GETMODIFIERS -- get modifier flags 130590792Sgshapiro** 130690792Sgshapiro** Parameters: 130790792Sgshapiro** v -- the modifiers (input text line). 130890792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 130990792Sgshapiro** 131090792Sgshapiro** Returns: 131190792Sgshapiro** (xallocat()ed) string representation of modifiers. 131290792Sgshapiro** 131390792Sgshapiro** Side Effects: 131490792Sgshapiro** fills in modifiers. 131590792Sgshapiro*/ 131690792Sgshapiro 131790792Sgshapirochar * 131890792Sgshapirogetmodifiers(v, modifiers) 131990792Sgshapiro char *v; 132090792Sgshapiro BITMAP256 modifiers; 132190792Sgshapiro{ 132290792Sgshapiro int l; 132390792Sgshapiro char *h, *f, *flags; 132490792Sgshapiro 132590792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 132690792Sgshapiro l = 3 * strlen(v) + 3; 132790792Sgshapiro 132890792Sgshapiro /* is someone joking? */ 132990792Sgshapiro if (l < 0 || l > 256) 133090792Sgshapiro { 133190792Sgshapiro if (LogLevel > 2) 133290792Sgshapiro sm_syslog(LOG_ERR, NOQID, 133390792Sgshapiro "getmodifiers too long, ignored"); 133490792Sgshapiro return NULL; 133590792Sgshapiro } 133690792Sgshapiro flags = xalloc(l); 133790792Sgshapiro f = flags; 133890792Sgshapiro clrbitmap(modifiers); 133990792Sgshapiro for (h = v; *h != '\0'; h++) 134090792Sgshapiro { 134190792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 134290792Sgshapiro { 134390792Sgshapiro setbitn(*h, modifiers); 134490792Sgshapiro if (flags != f) 134590792Sgshapiro *flags++ = ' '; 134690792Sgshapiro *flags++ = *h; 134790792Sgshapiro if (isupper(*h)) 134890792Sgshapiro *flags++ = *h; 134990792Sgshapiro } 135090792Sgshapiro } 135190792Sgshapiro *flags++ = '\0'; 135290792Sgshapiro return f; 135390792Sgshapiro} 135490792Sgshapiro 135590792Sgshapiro/* 135690792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 135790792Sgshapiro** 135890792Sgshapiro** Parameters: 135990792Sgshapiro** flag -- the flag to test. 136090792Sgshapiro** 136190792Sgshapiro** Returns: 136290792Sgshapiro** true iff all daemons have set flag. 136390792Sgshapiro*/ 136490792Sgshapiro 136590792Sgshapirobool 136690792Sgshapirochkdaemonmodifiers(flag) 136790792Sgshapiro int flag; 136890792Sgshapiro{ 136990792Sgshapiro int i; 137090792Sgshapiro 137190792Sgshapiro for (i = 0; i < NDaemons; i++) 137290792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 137390792Sgshapiro return false; 137490792Sgshapiro return true; 137590792Sgshapiro} 137690792Sgshapiro 137790792Sgshapiro/* 137864562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 137938032Speter** 138038032Speter** Parameters: 138138032Speter** p -- the options line. 138264562Sgshapiro** d -- the daemon structure to fill in. 138338032Speter** 138438032Speter** Returns: 138538032Speter** none. 138638032Speter*/ 138738032Speter 138864562Sgshapirostatic void 138964562Sgshapirosetsockaddroptions(p, d) 139038032Speter register char *p; 139190792Sgshapiro DAEMON_T *d; 139238032Speter{ 139390792Sgshapiro#if NETISO 139471345Sgshapiro short portno; 139590792Sgshapiro#endif /* NETISO */ 139671345Sgshapiro char *port = NULL; 139771345Sgshapiro char *addr = NULL; 139838032Speter 139990792Sgshapiro#if NETINET 140064562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 140164562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 140290792Sgshapiro#endif /* NETINET */ 140364562Sgshapiro 140438032Speter while (p != NULL) 140538032Speter { 140638032Speter register char *f; 140738032Speter register char *v; 140838032Speter 140938032Speter while (isascii(*p) && isspace(*p)) 141038032Speter p++; 141138032Speter if (*p == '\0') 141238032Speter break; 141338032Speter f = p; 141438032Speter p = strchr(p, ','); 141538032Speter if (p != NULL) 141638032Speter *p++ = '\0'; 141738032Speter v = strchr(f, '='); 141838032Speter if (v == NULL) 141938032Speter continue; 142038032Speter while (isascii(*++v) && isspace(*v)) 142138032Speter continue; 142238032Speter if (isascii(*f) && islower(*f)) 142338032Speter *f = toupper(*f); 142438032Speter 142538032Speter switch (*f) 142638032Speter { 142738032Speter case 'F': /* address family */ 142838032Speter if (isascii(*v) && isdigit(*v)) 142964562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 143090792Sgshapiro#if _FFR_DAEMON_NETUNIX 143190792Sgshapiro# ifdef NETUNIX 143290792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 143390792Sgshapiro sm_strcasecmp(v, "local") == 0) 143490792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 143590792Sgshapiro# endif /* NETUNIX */ 143690792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 143790792Sgshapiro#if NETINET 143890792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 143964562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 144090792Sgshapiro#endif /* NETINET */ 144190792Sgshapiro#if NETINET6 144290792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 144364562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 144490792Sgshapiro#endif /* NETINET6 */ 144590792Sgshapiro#if NETISO 144690792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 144764562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 144890792Sgshapiro#endif /* NETISO */ 144990792Sgshapiro#if NETNS 145090792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 145164562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 145290792Sgshapiro#endif /* NETNS */ 145390792Sgshapiro#if NETX25 145490792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 145564562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 145690792Sgshapiro#endif /* NETX25 */ 145738032Speter else 145864562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 145964562Sgshapiro v); 146038032Speter break; 146138032Speter 146238032Speter case 'A': /* address */ 146371345Sgshapiro addr = v; 146438032Speter break; 146538032Speter 146690792Sgshapiro#if MILTER 146790792Sgshapiro# if _FFR_MILTER_PERDAEMON 146890792Sgshapiro case 'I': 146990792Sgshapiro d->d_inputfilterlist = v; 147090792Sgshapiro break; 147190792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 147290792Sgshapiro#endif /* MILTER */ 147390792Sgshapiro 147438032Speter case 'P': /* port */ 147571345Sgshapiro port = v; 147638032Speter break; 147738032Speter 147838032Speter case 'L': /* listen queue size */ 147964562Sgshapiro d->d_listenqueue = atoi(v); 148038032Speter break; 148138032Speter 148264562Sgshapiro case 'M': /* modifiers (flags) */ 148390792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 148464562Sgshapiro break; 148564562Sgshapiro 148638032Speter case 'S': /* send buffer size */ 148764562Sgshapiro d->d_tcpsndbufsize = atoi(v); 148838032Speter break; 148938032Speter 149038032Speter case 'R': /* receive buffer size */ 149164562Sgshapiro d->d_tcprcvbufsize = atoi(v); 149238032Speter break; 149338032Speter 149464562Sgshapiro case 'N': /* name */ 149564562Sgshapiro d->d_name = v; 149664562Sgshapiro break; 149764562Sgshapiro 149838032Speter default: 149964562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 150064562Sgshapiro f); 150138032Speter } 150238032Speter } 150371345Sgshapiro 150471345Sgshapiro /* Check addr and port after finding family */ 150571345Sgshapiro if (addr != NULL) 150671345Sgshapiro { 150771345Sgshapiro switch (d->d_addr.sa.sa_family) 150871345Sgshapiro { 150990792Sgshapiro#if _FFR_DAEMON_NETUNIX 151090792Sgshapiro# if NETUNIX 151190792Sgshapiro case AF_UNIX: 151290792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 151390792Sgshapiro { 151490792Sgshapiro errno = ENAMETOOLONG; 151590792Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %d", 151690792Sgshapiro addr, sizeof(d->d_addr.sunix.sun_path)); 151790792Sgshapiro break; 151890792Sgshapiro } 151990792Sgshapiro 152090792Sgshapiro /* file safety check done in opendaemonsocket() */ 152190792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 152290792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 152390792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 152490792Sgshapiro addr, 152590792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 152690792Sgshapiro break; 152790792Sgshapiro# endif /* NETUNIX */ 152890792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 152990792Sgshapiro#if NETINET 153071345Sgshapiro case AF_INET: 153171345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 153290792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 153390792Sgshapiro == INADDR_NONE)) 153471345Sgshapiro { 153571345Sgshapiro register struct hostent *hp; 153671345Sgshapiro 153771345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 153871345Sgshapiro if (hp == NULL) 153971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 154071345Sgshapiro addr); 154171345Sgshapiro else 154271345Sgshapiro { 154371345Sgshapiro while (*(hp->h_addr_list) != NULL && 154471345Sgshapiro hp->h_addrtype != AF_INET) 154571345Sgshapiro hp->h_addr_list++; 154671345Sgshapiro if (*(hp->h_addr_list) == NULL) 154771345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 154871345Sgshapiro addr); 154971345Sgshapiro else 155071345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 155171345Sgshapiro *(hp->h_addr_list), 155271345Sgshapiro INADDRSZ); 155390792Sgshapiro# if NETINET6 155471345Sgshapiro freehostent(hp); 155571345Sgshapiro hp = NULL; 155690792Sgshapiro# endif /* NETINET6 */ 155771345Sgshapiro } 155871345Sgshapiro } 155971345Sgshapiro break; 156090792Sgshapiro#endif /* NETINET */ 156171345Sgshapiro 156290792Sgshapiro#if NETINET6 156371345Sgshapiro case AF_INET6: 156490792Sgshapiro if (anynet_pton(AF_INET6, addr, 156590792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 156671345Sgshapiro { 156771345Sgshapiro register struct hostent *hp; 156871345Sgshapiro 156971345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 157071345Sgshapiro if (hp == NULL) 157171345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 157271345Sgshapiro addr); 157371345Sgshapiro else 157471345Sgshapiro { 157571345Sgshapiro while (*(hp->h_addr_list) != NULL && 157671345Sgshapiro hp->h_addrtype != AF_INET6) 157771345Sgshapiro hp->h_addr_list++; 157871345Sgshapiro if (*(hp->h_addr_list) == NULL) 157971345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 158071345Sgshapiro addr); 158171345Sgshapiro else 158271345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 158371345Sgshapiro *(hp->h_addr_list), 158471345Sgshapiro IN6ADDRSZ); 158571345Sgshapiro freehostent(hp); 158671345Sgshapiro hp = NULL; 158771345Sgshapiro } 158871345Sgshapiro } 158971345Sgshapiro break; 159090792Sgshapiro#endif /* NETINET6 */ 159171345Sgshapiro 159271345Sgshapiro default: 159371345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 159471345Sgshapiro d->d_addr.sa.sa_family); 159571345Sgshapiro break; 159671345Sgshapiro } 159771345Sgshapiro } 159871345Sgshapiro 159971345Sgshapiro if (port != NULL) 160071345Sgshapiro { 160171345Sgshapiro switch (d->d_addr.sa.sa_family) 160271345Sgshapiro { 160390792Sgshapiro#if NETINET 160471345Sgshapiro case AF_INET: 160571345Sgshapiro if (isascii(*port) && isdigit(*port)) 160690792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 160790792Sgshapiro atoi((const char *) port)); 160871345Sgshapiro else 160971345Sgshapiro { 161090792Sgshapiro# ifdef NO_GETSERVBYNAME 161171345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 161271345Sgshapiro port); 161390792Sgshapiro# else /* NO_GETSERVBYNAME */ 161471345Sgshapiro register struct servent *sp; 161571345Sgshapiro 161671345Sgshapiro sp = getservbyname(port, "tcp"); 161771345Sgshapiro if (sp == NULL) 161871345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 161971345Sgshapiro port); 162071345Sgshapiro else 162171345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 162290792Sgshapiro# endif /* NO_GETSERVBYNAME */ 162371345Sgshapiro } 162471345Sgshapiro break; 162590792Sgshapiro#endif /* NETINET */ 162671345Sgshapiro 162790792Sgshapiro#if NETINET6 162871345Sgshapiro case AF_INET6: 162971345Sgshapiro if (isascii(*port) && isdigit(*port)) 163090792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 163190792Sgshapiro atoi(port)); 163271345Sgshapiro else 163371345Sgshapiro { 163490792Sgshapiro# ifdef NO_GETSERVBYNAME 163571345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 163671345Sgshapiro port); 163790792Sgshapiro# else /* NO_GETSERVBYNAME */ 163871345Sgshapiro register struct servent *sp; 163971345Sgshapiro 164071345Sgshapiro sp = getservbyname(port, "tcp"); 164171345Sgshapiro if (sp == NULL) 164271345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 164371345Sgshapiro port); 164471345Sgshapiro else 164571345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 164690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 164771345Sgshapiro } 164871345Sgshapiro break; 164990792Sgshapiro#endif /* NETINET6 */ 165071345Sgshapiro 165190792Sgshapiro#if NETISO 165271345Sgshapiro case AF_ISO: 165371345Sgshapiro /* assume two byte transport selector */ 165471345Sgshapiro if (isascii(*port) && isdigit(*port)) 165590792Sgshapiro portno = htons((unsigned short) atoi(port)); 165671345Sgshapiro else 165771345Sgshapiro { 165890792Sgshapiro# ifdef NO_GETSERVBYNAME 165971345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 166071345Sgshapiro port); 166190792Sgshapiro# else /* NO_GETSERVBYNAME */ 166271345Sgshapiro register struct servent *sp; 166371345Sgshapiro 166471345Sgshapiro sp = getservbyname(port, "tcp"); 166571345Sgshapiro if (sp == NULL) 166671345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 166771345Sgshapiro port); 166871345Sgshapiro else 166971345Sgshapiro portno = sp->s_port; 167090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 167171345Sgshapiro } 167271345Sgshapiro memmove(TSEL(&d->d_addr.siso), 167371345Sgshapiro (char *) &portno, 2); 167471345Sgshapiro break; 167590792Sgshapiro#endif /* NETISO */ 167671345Sgshapiro 167771345Sgshapiro default: 167871345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 167971345Sgshapiro d->d_addr.sa.sa_family); 168071345Sgshapiro break; 168171345Sgshapiro } 168271345Sgshapiro } 168338032Speter} 168490792Sgshapiro/* 168564562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 168638032Speter** 168738032Speter** Parameters: 168864562Sgshapiro** p -- the options line. 168964562Sgshapiro** 169064562Sgshapiro** Returns: 169190792Sgshapiro** true if successful, false otherwise. 169290792Sgshapiro** 169390792Sgshapiro** Side Effects: 169490792Sgshapiro** increments number of daemons. 169564562Sgshapiro*/ 169664562Sgshapiro 169790792Sgshapiro#define DEF_LISTENQUEUE 10 169890792Sgshapiro 169998841Sgshapirostruct dflags 170098841Sgshapiro{ 170198841Sgshapiro char *d_name; 170298841Sgshapiro int d_flag; 170398841Sgshapiro}; 170498841Sgshapiro 170598841Sgshapirostatic struct dflags DaemonFlags[] = 170698841Sgshapiro{ 170798841Sgshapiro { "AUTHREQ", D_AUTHREQ }, 170898841Sgshapiro { "BINDIF", D_BINDIF }, 170998841Sgshapiro { "CANONREQ", D_CANONREQ }, 171098841Sgshapiro { "IFNHELO", D_IFNHELO }, 171198841Sgshapiro { "FQMAIL", D_FQMAIL }, 171298841Sgshapiro { "FQRCPT", D_FQRCPT }, 171398841Sgshapiro#if _FFR_SMTP_SSL 171498841Sgshapiro { "SMTPS", D_SMTPS }, 171598841Sgshapiro#endif /* _FFR_SMTP_SSL */ 171698841Sgshapiro { "UNQUALOK", D_UNQUALOK }, 171798841Sgshapiro { "NOAUTH", D_NOAUTH }, 171898841Sgshapiro { "NOCANON", D_NOCANON }, 171998841Sgshapiro { "NOETRN", D_NOETRN }, 172098841Sgshapiro { "NOTLS", D_NOTLS }, 172198841Sgshapiro { "ETRNONLY", D_ETRNONLY }, 172298841Sgshapiro { "OPTIONAL", D_OPTIONAL }, 172398841Sgshapiro { "DISABLE", D_DISABLE }, 172498841Sgshapiro { "ISSET", D_ISSET }, 172598841Sgshapiro { NULL, 0 } 172698841Sgshapiro}; 172798841Sgshapiro 172898841Sgshapirostatic void 172998841Sgshapiroprintdaemonflags(d) 173098841Sgshapiro DAEMON_T *d; 173198841Sgshapiro{ 173298841Sgshapiro register struct dflags *df; 173398841Sgshapiro bool first = true; 173498841Sgshapiro 173598841Sgshapiro for (df = DaemonFlags; df->d_name != NULL; df++) 173698841Sgshapiro { 173798841Sgshapiro if (!bitnset(df->d_flag, d->d_flags)) 173898841Sgshapiro continue; 173998841Sgshapiro if (first) 174098841Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "<%s", 174198841Sgshapiro df->d_name); 174298841Sgshapiro else 174398841Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ",%s", 174498841Sgshapiro df->d_name); 174598841Sgshapiro first = false; 174698841Sgshapiro } 174798841Sgshapiro if (!first) 174898841Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">"); 174998841Sgshapiro} 175098841Sgshapiro 175164562Sgshapirobool 175264562Sgshapirosetdaemonoptions(p) 175364562Sgshapiro register char *p; 175464562Sgshapiro{ 175590792Sgshapiro if (NDaemons >= MAXDAEMONS) 175690792Sgshapiro return false; 175790792Sgshapiro Daemons[NDaemons].d_socket = -1; 175890792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 175990792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 176090792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 176164562Sgshapiro 176290792Sgshapiro#if MILTER 176390792Sgshapiro# if _FFR_MILTER_PERDAEMON 176490792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 176590792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 176690792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 176790792Sgshapiro#endif /* MILTER */ 176890792Sgshapiro 176990792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 177090792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 177164562Sgshapiro else 177264562Sgshapiro { 177364562Sgshapiro char num[30]; 177464562Sgshapiro 177590792Sgshapiro (void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons); 177690792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 177764562Sgshapiro } 177864562Sgshapiro 177964562Sgshapiro if (tTd(37, 1)) 178064562Sgshapiro { 178190792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 178298841Sgshapiro printdaemonflags(&Daemons[NDaemons]); 178390792Sgshapiro sm_dprintf("\n"); 178464562Sgshapiro } 178590792Sgshapiro ++NDaemons; 178690792Sgshapiro return true; 178764562Sgshapiro} 178890792Sgshapiro/* 178964562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 179064562Sgshapiro** 179164562Sgshapiro** Parameters: 179264562Sgshapiro** none 179364562Sgshapiro** 179464562Sgshapiro** Returns: 179564562Sgshapiro** none 179664562Sgshapiro** 179764562Sgshapiro** Side Effects: 179864562Sgshapiro** initializes structure for one daemon. 179964562Sgshapiro*/ 180090792Sgshapiro 180164562Sgshapirovoid 180264562Sgshapiroinitdaemon() 180364562Sgshapiro{ 180490792Sgshapiro if (NDaemons == 0) 180564562Sgshapiro { 180690792Sgshapiro Daemons[NDaemons].d_socket = -1; 180790792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 180890792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 180990792Sgshapiro NDaemons = 1; 181064562Sgshapiro } 181164562Sgshapiro} 181290792Sgshapiro/* 181364562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 181464562Sgshapiro** 181564562Sgshapiro** Parameters: 181664562Sgshapiro** p -- the options line. 181764562Sgshapiro** 181864562Sgshapiro** Returns: 181964562Sgshapiro** none. 182064562Sgshapiro*/ 182164562Sgshapiro 182290792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 182364562Sgshapiro 182464562Sgshapirovoid 182564562Sgshapirosetclientoptions(p) 182664562Sgshapiro register char *p; 182764562Sgshapiro{ 182890792Sgshapiro int family; 182990792Sgshapiro DAEMON_T d; 183064562Sgshapiro 183164562Sgshapiro memset(&d, '\0', sizeof d); 183264562Sgshapiro setsockaddroptions(p, &d); 183364562Sgshapiro 183464562Sgshapiro /* grab what we need */ 183590792Sgshapiro family = d.d_addr.sa.sa_family; 183690792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 183790792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 183890792Sgshapiro if (d.d_name != NULL) 183990792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 184064562Sgshapiro else 184190792Sgshapiro { 184290792Sgshapiro char num[30]; 184390792Sgshapiro 184490792Sgshapiro (void) sm_snprintf(num, sizeof num, "Client%d", family); 184590792Sgshapiro ClientSettings[family].d_name = newstr(num); 184690792Sgshapiro } 184764562Sgshapiro} 184890792Sgshapiro/* 184964562Sgshapiro** ADDR_FAMILY -- determine address family from address 185064562Sgshapiro** 185164562Sgshapiro** Parameters: 185264562Sgshapiro** addr -- the string representation of the address 185364562Sgshapiro** 185464562Sgshapiro** Returns: 185564562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 185664562Sgshapiro** 185764562Sgshapiro** Side Effects: 185864562Sgshapiro** none. 185964562Sgshapiro*/ 186064562Sgshapiro 186164562Sgshapirostatic int 186264562Sgshapiroaddr_family(addr) 186364562Sgshapiro char *addr; 186464562Sgshapiro{ 186590792Sgshapiro#if NETINET6 186664562Sgshapiro SOCKADDR clt_addr; 186790792Sgshapiro#endif /* NETINET6 */ 186864562Sgshapiro 186990792Sgshapiro#if NETINET 187064562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 187164562Sgshapiro { 187264562Sgshapiro if (tTd(16, 9)) 187390792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 187464562Sgshapiro return AF_INET; 187564562Sgshapiro } 187690792Sgshapiro#endif /* NETINET */ 187790792Sgshapiro#if NETINET6 187890792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 187964562Sgshapiro { 188064562Sgshapiro if (tTd(16, 9)) 188190792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 188264562Sgshapiro return AF_INET6; 188364562Sgshapiro } 188490792Sgshapiro#endif /* NETINET6 */ 188590792Sgshapiro#if _FFR_DAEMON_NETUNIX 188690792Sgshapiro# if NETUNIX 188790792Sgshapiro if (*addr == '/') 188890792Sgshapiro { 188990792Sgshapiro if (tTd(16, 9)) 189090792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 189190792Sgshapiro return AF_UNIX; 189290792Sgshapiro } 189390792Sgshapiro# endif /* NETUNIX */ 189490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 189564562Sgshapiro if (tTd(16, 9)) 189690792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 189764562Sgshapiro return AF_UNSPEC; 189864562Sgshapiro} 189990792Sgshapiro 190090792Sgshapiro/* 190190792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 190290792Sgshapiro** 190390792Sgshapiro** Parameters: 190490792Sgshapiro** flag -- the flag to test. 190590792Sgshapiro** 190690792Sgshapiro** Returns: 190790792Sgshapiro** true iff all configured clients have set the flag. 190890792Sgshapiro*/ 190990792Sgshapiro 191090792Sgshapirobool 191190792Sgshapirochkclientmodifiers(flag) 191290792Sgshapiro int flag; 191390792Sgshapiro{ 191490792Sgshapiro int i; 191590792Sgshapiro bool flagisset; 191690792Sgshapiro 191790792Sgshapiro flagisset = false; 191890792Sgshapiro for (i = 0; i < AF_MAX; i++) 191990792Sgshapiro { 192090792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 192190792Sgshapiro { 192290792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 192390792Sgshapiro return false; 192490792Sgshapiro flagisset = true; 192590792Sgshapiro } 192690792Sgshapiro } 192790792Sgshapiro return flagisset; 192890792Sgshapiro} 192990792Sgshapiro 193090792Sgshapiro#if MILTER 193190792Sgshapiro# if _FFR_MILTER_PERDAEMON 193290792Sgshapiro/* 193390792Sgshapiro** SETUP_DAEMON_FILTERS -- Parse per-socket filters 193490792Sgshapiro** 193590792Sgshapiro** Parameters: 193690792Sgshapiro** none 193790792Sgshapiro** 193890792Sgshapiro** Returns: 193990792Sgshapiro** none 194090792Sgshapiro*/ 194190792Sgshapiro 194290792Sgshapirovoid 194390792Sgshapirosetup_daemon_milters() 194490792Sgshapiro{ 194590792Sgshapiro int idx; 194690792Sgshapiro 194790792Sgshapiro if (OpMode == MD_SMTP) 194890792Sgshapiro { 194990792Sgshapiro /* no need to configure the daemons */ 195090792Sgshapiro return; 195190792Sgshapiro } 195290792Sgshapiro 195390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 195490792Sgshapiro { 195590792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 195690792Sgshapiro { 195790792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 195890792Sgshapiro Daemons[idx].d_inputfilters, 195990792Sgshapiro MAXFILTERS); 196090792Sgshapiro } 196190792Sgshapiro } 196290792Sgshapiro} 196390792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 196490792Sgshapiro#endif /* MILTER */ 196590792Sgshapiro/* 196664562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 196764562Sgshapiro** 196864562Sgshapiro** Parameters: 196938032Speter** host -- the name of the host. 197038032Speter** port -- the port number to connect to. 197138032Speter** mci -- a pointer to the mail connection information 197238032Speter** structure to be filled in. 197338032Speter** e -- the current envelope. 197490792Sgshapiro** enough -- time at which to stop further connection attempts. 197590792Sgshapiro** (0 means no limit) 197638032Speter** 197738032Speter** Returns: 197838032Speter** An exit code telling whether the connection could be 197938032Speter** made and if not why not. 198038032Speter** 198138032Speter** Side Effects: 198238032Speter** none. 198338032Speter*/ 198438032Speter 198538032Speterstatic jmp_buf CtxConnectTimeout; 198638032Speter 198738032SpeterSOCKADDR CurHostAddr; /* address of current host */ 198838032Speter 198938032Speterint 199090792Sgshapiromakeconnection(host, port, mci, e, enough) 199138032Speter char *host; 199290792Sgshapiro volatile unsigned int port; 199338032Speter register MCI *mci; 199438032Speter ENVELOPE *e; 199590792Sgshapiro time_t enough; 199638032Speter{ 199738032Speter register volatile int addrno = 0; 199890792Sgshapiro volatile int s; 199990792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 200038032Speter SOCKADDR addr; 200164562Sgshapiro SOCKADDR clt_addr; 200264562Sgshapiro int save_errno = 0; 200364562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 200438032Speter volatile bool firstconnect; 200590792Sgshapiro SM_EVENT *volatile ev = NULL; 200690792Sgshapiro#if NETINET6 200790792Sgshapiro volatile bool v6found = false; 200890792Sgshapiro#endif /* NETINET6 */ 200964562Sgshapiro volatile int family = InetMode; 201064562Sgshapiro SOCKADDR_LEN_T len; 201164562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 201264562Sgshapiro volatile bool clt_bind; 201364562Sgshapiro BITMAP256 d_flags; 201464562Sgshapiro char *p; 201564562Sgshapiro extern ENVELOPE BlankEnvelope; 201638032Speter 201790792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 201864562Sgshapiro clrbitmap(d_flags); 201990792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 202064562Sgshapiro { 202164562Sgshapiro for (; *p != '\0'; p++) 202264562Sgshapiro { 202364562Sgshapiro if (!(isascii(*p) && isspace(*p))) 202471345Sgshapiro setbitn(bitidx(*p), d_flags); 202564562Sgshapiro } 202664562Sgshapiro } 202764562Sgshapiro 202890792Sgshapiro#if NETINET6 202964562Sgshapiro v4retry: 203090792Sgshapiro#endif /* NETINET6 */ 203190792Sgshapiro clt_bind = false; 203264562Sgshapiro 203364562Sgshapiro /* Set up the address for outgoing connection. */ 203464562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 203590792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 203673188Sgshapiro *p != '\0') 203764562Sgshapiro { 203890792Sgshapiro#if NETINET6 203964562Sgshapiro char p6[INET6_ADDRSTRLEN]; 204090792Sgshapiro#endif /* NETINET6 */ 204164562Sgshapiro 204264562Sgshapiro memset(&clt_addr, '\0', sizeof clt_addr); 204364562Sgshapiro 204464562Sgshapiro /* infer the address family from the address itself */ 204564562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 204664562Sgshapiro switch (clt_addr.sa.sa_family) 204764562Sgshapiro { 204890792Sgshapiro#if NETINET 204964562Sgshapiro case AF_INET: 205073188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 205173188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 205273188Sgshapiro clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK) 205364562Sgshapiro { 205490792Sgshapiro clt_bind = true; 205564562Sgshapiro socksize = sizeof (struct sockaddr_in); 205664562Sgshapiro } 205764562Sgshapiro break; 205890792Sgshapiro#endif /* NETINET */ 205964562Sgshapiro 206090792Sgshapiro#if NETINET6 206164562Sgshapiro case AF_INET6: 206264562Sgshapiro if (inet_addr(p) != INADDR_NONE) 206390792Sgshapiro (void) sm_snprintf(p6, sizeof p6, 206490792Sgshapiro "IPv6:::ffff:%s", p); 206564562Sgshapiro else 206690792Sgshapiro (void) sm_strlcpy(p6, p, sizeof p6); 206790792Sgshapiro if (anynet_pton(AF_INET6, p6, 206890792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 206973188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 207064562Sgshapiro { 207190792Sgshapiro clt_bind = true; 207264562Sgshapiro socksize = sizeof (struct sockaddr_in6); 207364562Sgshapiro } 207464562Sgshapiro break; 207590792Sgshapiro#endif /* NETINET6 */ 207664562Sgshapiro 207790792Sgshapiro#if 0 207864562Sgshapiro default: 207964562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 208064562Sgshapiro clt_addr.sa.sa_family); 208164562Sgshapiro break; 208290792Sgshapiro#endif /* 0 */ 208364562Sgshapiro } 208464562Sgshapiro if (clt_bind) 208564562Sgshapiro family = clt_addr.sa.sa_family; 208664562Sgshapiro } 208790792Sgshapiro 208890792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 208990792Sgshapiro if (!clt_bind) 209064562Sgshapiro { 209190792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 209264562Sgshapiro switch (clt_addr.sa.sa_family) 209364562Sgshapiro { 209490792Sgshapiro#if NETINET 209564562Sgshapiro case AF_INET: 209664562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 209764562Sgshapiro clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 209864562Sgshapiro else 209990792Sgshapiro clt_bind = true; 210064562Sgshapiro if (clt_addr.sin.sin_port != 0) 210190792Sgshapiro clt_bind = true; 210264562Sgshapiro socksize = sizeof (struct sockaddr_in); 210364562Sgshapiro break; 210490792Sgshapiro#endif /* NETINET */ 210590792Sgshapiro#if NETINET6 210664562Sgshapiro case AF_INET6: 210764562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 210864562Sgshapiro clt_addr.sin6.sin6_addr = in6addr_any; 210964562Sgshapiro else 211090792Sgshapiro clt_bind = true; 211164562Sgshapiro socksize = sizeof (struct sockaddr_in6); 211264562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 211390792Sgshapiro clt_bind = true; 211464562Sgshapiro break; 211590792Sgshapiro#endif /* NETINET6 */ 211690792Sgshapiro#if NETISO 211764562Sgshapiro case AF_ISO: 211864562Sgshapiro socksize = sizeof clt_addr.siso; 211990792Sgshapiro clt_bind = true; 212064562Sgshapiro break; 212190792Sgshapiro#endif /* NETISO */ 212264562Sgshapiro default: 212364562Sgshapiro break; 212464562Sgshapiro } 212564562Sgshapiro } 212664562Sgshapiro 212738032Speter /* 212838032Speter ** Set up the address for the mailer. 212938032Speter ** Accept "[a.b.c.d]" syntax for host name. 213038032Speter */ 213138032Speter 213273188Sgshapiro SM_SET_H_ERRNO(0); 213338032Speter errno = 0; 213464562Sgshapiro memset(&CurHostAddr, '\0', sizeof CurHostAddr); 213564562Sgshapiro memset(&addr, '\0', sizeof addr); 213638032Speter SmtpPhase = mci->mci_phase = "initial connection"; 213738032Speter CurHostName = host; 213838032Speter 213938032Speter if (host[0] == '[') 214038032Speter { 214164562Sgshapiro p = strchr(host, ']'); 214238032Speter if (p != NULL) 214338032Speter { 214490792Sgshapiro#if NETINET 214564562Sgshapiro unsigned long hid = INADDR_NONE; 214690792Sgshapiro#endif /* NETINET */ 214790792Sgshapiro#if NETINET6 214864562Sgshapiro struct sockaddr_in6 hid6; 214990792Sgshapiro#endif /* NETINET6 */ 215064562Sgshapiro 215138032Speter *p = '\0'; 215290792Sgshapiro#if NETINET6 215364562Sgshapiro memset(&hid6, '\0', sizeof hid6); 215490792Sgshapiro#endif /* NETINET6 */ 215590792Sgshapiro#if NETINET 215664562Sgshapiro if (family == AF_INET && 215764562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 215838032Speter { 215964562Sgshapiro addr.sin.sin_family = AF_INET; 216064562Sgshapiro addr.sin.sin_addr.s_addr = hid; 216164562Sgshapiro } 216264562Sgshapiro else 216390792Sgshapiro#endif /* NETINET */ 216490792Sgshapiro#if NETINET6 216564562Sgshapiro if (family == AF_INET6 && 216690792Sgshapiro anynet_pton(AF_INET6, &host[1], 216790792Sgshapiro &hid6.sin6_addr) == 1) 216864562Sgshapiro { 216964562Sgshapiro addr.sin6.sin6_family = AF_INET6; 217064562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 217164562Sgshapiro } 217264562Sgshapiro else 217390792Sgshapiro#endif /* NETINET6 */ 217464562Sgshapiro { 217538032Speter /* try it as a host name (avoid MX lookup) */ 217664562Sgshapiro hp = sm_gethostbyname(&host[1], family); 217738032Speter if (hp == NULL && p[-1] == '.') 217838032Speter { 217990792Sgshapiro#if NAMED_BIND 218038032Speter int oldopts = _res.options; 218138032Speter 218238032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 218390792Sgshapiro#endif /* NAMED_BIND */ 218438032Speter p[-1] = '\0'; 218564562Sgshapiro hp = sm_gethostbyname(&host[1], 218664562Sgshapiro family); 218738032Speter p[-1] = '.'; 218890792Sgshapiro#if NAMED_BIND 218938032Speter _res.options = oldopts; 219090792Sgshapiro#endif /* NAMED_BIND */ 219138032Speter } 219238032Speter *p = ']'; 219338032Speter goto gothostent; 219438032Speter } 219538032Speter *p = ']'; 219638032Speter } 219738032Speter if (p == NULL) 219838032Speter { 219938032Speter extern char MsgBuf[]; 220038032Speter 220164562Sgshapiro usrerrenh("5.1.2", 220264562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 220364562Sgshapiro host); 220438032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 220564562Sgshapiro errno = EINVAL; 220638032Speter return EX_NOHOST; 220738032Speter } 220838032Speter } 220938032Speter else 221038032Speter { 221138032Speter /* contortion to get around SGI cc complaints */ 221238032Speter { 221364562Sgshapiro p = &host[strlen(host) - 1]; 221464562Sgshapiro hp = sm_gethostbyname(host, family); 221538032Speter if (hp == NULL && *p == '.') 221638032Speter { 221790792Sgshapiro#if NAMED_BIND 221838032Speter int oldopts = _res.options; 221938032Speter 222038032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 222190792Sgshapiro#endif /* NAMED_BIND */ 222238032Speter *p = '\0'; 222364562Sgshapiro hp = sm_gethostbyname(host, family); 222438032Speter *p = '.'; 222590792Sgshapiro#if NAMED_BIND 222638032Speter _res.options = oldopts; 222790792Sgshapiro#endif /* NAMED_BIND */ 222838032Speter } 222938032Speter } 223038032Spetergothostent: 223138032Speter if (hp == NULL) 223238032Speter { 223390792Sgshapiro#if NAMED_BIND 223438032Speter /* check for name server timeouts */ 223590792Sgshapiro# if NETINET6 223690792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 223790792Sgshapiro errno == ETIMEDOUT) 223838032Speter { 223990792Sgshapiro /* 224090792Sgshapiro ** An attempt with family AF_INET may 224190792Sgshapiro ** succeed By skipping the next section 224290792Sgshapiro ** of code, we will try AF_INET before 224390792Sgshapiro ** failing. 224490792Sgshapiro */ 224590792Sgshapiro 224690792Sgshapiro if (tTd(16, 10)) 224790792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 224838032Speter } 224990792Sgshapiro else 225090792Sgshapiro# endif /* NETINET6 */ 225190792Sgshapiro { 225290792Sgshapiro if (errno == ETIMEDOUT || 225390792Sgshapiro h_errno == TRY_AGAIN || 225490792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 225590792Sgshapiro { 225690792Sgshapiro save_errno = errno; 225790792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 225890792Sgshapiro "4.4.3", NULL); 225990792Sgshapiro errno = save_errno; 226090792Sgshapiro return EX_TEMPFAIL; 226190792Sgshapiro } 226290792Sgshapiro } 226390792Sgshapiro#endif /* NAMED_BIND */ 226490792Sgshapiro#if NETINET6 226564562Sgshapiro /* 226664562Sgshapiro ** Try v6 first, then fall back to v4. 226764562Sgshapiro ** If we found a v6 address, but no v4 226864562Sgshapiro ** addresses, then TEMPFAIL. 226964562Sgshapiro */ 227064562Sgshapiro 227164562Sgshapiro if (family == AF_INET6) 227264562Sgshapiro { 227364562Sgshapiro family = AF_INET; 227464562Sgshapiro goto v4retry; 227564562Sgshapiro } 227664562Sgshapiro if (v6found) 227764562Sgshapiro goto v6tempfail; 227890792Sgshapiro#endif /* NETINET6 */ 227964562Sgshapiro save_errno = errno; 228038032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 228164562Sgshapiro errno = save_errno; 228264562Sgshapiro return EX_NOHOST; 228338032Speter } 228438032Speter addr.sa.sa_family = hp->h_addrtype; 228538032Speter switch (hp->h_addrtype) 228638032Speter { 228790792Sgshapiro#if NETINET 228838032Speter case AF_INET: 228964562Sgshapiro memmove(&addr.sin.sin_addr, 229064562Sgshapiro hp->h_addr, 229138032Speter INADDRSZ); 229238032Speter break; 229390792Sgshapiro#endif /* NETINET */ 229438032Speter 229590792Sgshapiro#if NETINET6 229664562Sgshapiro case AF_INET6: 229764562Sgshapiro memmove(&addr.sin6.sin6_addr, 229864562Sgshapiro hp->h_addr, 229964562Sgshapiro IN6ADDRSZ); 230064562Sgshapiro break; 230190792Sgshapiro#endif /* NETINET6 */ 230264562Sgshapiro 230338032Speter default: 230438032Speter if (hp->h_length > sizeof addr.sa.sa_data) 230538032Speter { 230638032Speter syserr("makeconnection: long sa_data: family %d len %d", 230738032Speter hp->h_addrtype, hp->h_length); 230838032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 230964562Sgshapiro errno = EINVAL; 231038032Speter return EX_NOHOST; 231138032Speter } 231290792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 231338032Speter break; 231438032Speter } 231538032Speter addrno = 1; 231638032Speter } 231738032Speter 231838032Speter /* 231938032Speter ** Determine the port number. 232038032Speter */ 232138032Speter 232238032Speter if (port == 0) 232338032Speter { 232490792Sgshapiro#ifdef NO_GETSERVBYNAME 232564562Sgshapiro port = htons(25); 232690792Sgshapiro#else /* NO_GETSERVBYNAME */ 232738032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 232838032Speter 232938032Speter if (sp == NULL) 233038032Speter { 233138032Speter if (LogLevel > 2) 233238032Speter sm_syslog(LOG_ERR, NOQID, 233364562Sgshapiro "makeconnection: service \"smtp\" unknown"); 233438032Speter port = htons(25); 233538032Speter } 233638032Speter else 233738032Speter port = sp->s_port; 233890792Sgshapiro#endif /* NO_GETSERVBYNAME */ 233938032Speter } 234038032Speter 234190792Sgshapiro#if NETINET6 234290792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 234390792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 234490792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 234590792Sgshapiro { 234690792Sgshapiro /* 234790792Sgshapiro ** Ignore mapped IPv4 address since 234890792Sgshapiro ** there is a ClientPortOptions setting 234990792Sgshapiro ** for IPv4. 235090792Sgshapiro */ 235190792Sgshapiro 235290792Sgshapiro goto nextaddr; 235390792Sgshapiro } 235490792Sgshapiro#endif /* NETINET6 */ 235590792Sgshapiro 235638032Speter switch (addr.sa.sa_family) 235738032Speter { 235890792Sgshapiro#if NETINET 235938032Speter case AF_INET: 236038032Speter addr.sin.sin_port = port; 236138032Speter addrlen = sizeof (struct sockaddr_in); 236238032Speter break; 236390792Sgshapiro#endif /* NETINET */ 236438032Speter 236590792Sgshapiro#if NETINET6 236664562Sgshapiro case AF_INET6: 236764562Sgshapiro addr.sin6.sin6_port = port; 236864562Sgshapiro addrlen = sizeof (struct sockaddr_in6); 236964562Sgshapiro break; 237090792Sgshapiro#endif /* NETINET6 */ 237164562Sgshapiro 237290792Sgshapiro#if NETISO 237338032Speter case AF_ISO: 237438032Speter /* assume two byte transport selector */ 237564562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 237638032Speter addrlen = sizeof (struct sockaddr_iso); 237738032Speter break; 237890792Sgshapiro#endif /* NETISO */ 237938032Speter 238038032Speter default: 238138032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 238238032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 238364562Sgshapiro errno = EINVAL; 238490792Sgshapiro#if NETINET6 238571345Sgshapiro if (hp != NULL) 238671345Sgshapiro freehostent(hp); 238790792Sgshapiro#endif /* NETINET6 */ 238864562Sgshapiro return EX_NOHOST; 238938032Speter } 239038032Speter 239138032Speter /* 239238032Speter ** Try to actually open the connection. 239338032Speter */ 239438032Speter 239590792Sgshapiro#if XLA 239638032Speter /* if too many connections, don't bother trying */ 239738032Speter if (!xla_noqueue_ok(host)) 239871345Sgshapiro { 239990792Sgshapiro# if NETINET6 240071345Sgshapiro if (hp != NULL) 240171345Sgshapiro freehostent(hp); 240290792Sgshapiro# endif /* NETINET6 */ 240338032Speter return EX_TEMPFAIL; 240471345Sgshapiro } 240590792Sgshapiro#endif /* XLA */ 240638032Speter 240790792Sgshapiro firstconnect = true; 240838032Speter for (;;) 240938032Speter { 241038032Speter if (tTd(16, 1)) 241190792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 241290792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 241390792Sgshapiro (int) addr.sa.sa_family); 241438032Speter 241538032Speter /* save for logging */ 241638032Speter CurHostAddr = addr; 241738032Speter 241890792Sgshapiro#if HASRRESVPORT 241938032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 242038032Speter { 242138032Speter int rport = IPPORT_RESERVED - 1; 242238032Speter 242338032Speter s = rresvport(&rport); 242438032Speter } 242538032Speter else 242690792Sgshapiro#endif /* HASRRESVPORT */ 242738032Speter { 242890792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 242938032Speter } 243038032Speter if (s < 0) 243138032Speter { 243264562Sgshapiro save_errno = errno; 243338032Speter syserr("makeconnection: cannot create socket"); 243490792Sgshapiro#if XLA 243538032Speter xla_host_end(host); 243690792Sgshapiro#endif /* XLA */ 243738032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 243890792Sgshapiro#if NETINET6 243971345Sgshapiro if (hp != NULL) 244071345Sgshapiro freehostent(hp); 244190792Sgshapiro#endif /* NETINET6 */ 244264562Sgshapiro errno = save_errno; 244338032Speter return EX_TEMPFAIL; 244438032Speter } 244538032Speter 244690792Sgshapiro#ifdef SO_SNDBUF 244790792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 244838032Speter { 244938032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 245090792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 245190792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 245238032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 245338032Speter } 245490792Sgshapiro#endif /* SO_SNDBUF */ 245590792Sgshapiro#ifdef SO_RCVBUF 245690792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 245764562Sgshapiro { 245864562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 245990792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 246090792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 246164562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 246264562Sgshapiro } 246390792Sgshapiro#endif /* SO_RCVBUF */ 246438032Speter 246538032Speter if (tTd(16, 1)) 246690792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 246738032Speter 246838032Speter /* turn on network debugging? */ 246938032Speter if (tTd(16, 101)) 247038032Speter { 247138032Speter int on = 1; 247264562Sgshapiro 247338032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 247438032Speter (char *)&on, sizeof on); 247538032Speter } 247690792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 247790792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 247890792Sgshapiro errno = 0; /* for debugging */ 247938032Speter 248064562Sgshapiro if (clt_bind) 248164562Sgshapiro { 248264562Sgshapiro int on = 1; 248364562Sgshapiro 248464562Sgshapiro switch (clt_addr.sa.sa_family) 248564562Sgshapiro { 248690792Sgshapiro#if NETINET 248764562Sgshapiro case AF_INET: 248864562Sgshapiro if (clt_addr.sin.sin_port != 0) 248964562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 249064562Sgshapiro SO_REUSEADDR, 249164562Sgshapiro (char *) &on, 249264562Sgshapiro sizeof on); 249364562Sgshapiro break; 249490792Sgshapiro#endif /* NETINET */ 249564562Sgshapiro 249690792Sgshapiro#if NETINET6 249764562Sgshapiro case AF_INET6: 249864562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 249964562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 250064562Sgshapiro SO_REUSEADDR, 250164562Sgshapiro (char *) &on, 250264562Sgshapiro sizeof on); 250364562Sgshapiro break; 250490792Sgshapiro#endif /* NETINET6 */ 250564562Sgshapiro } 250664562Sgshapiro 250764562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 250864562Sgshapiro { 250964562Sgshapiro save_errno = errno; 251064562Sgshapiro (void) close(s); 251164562Sgshapiro errno = save_errno; 251264562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 251364562Sgshapiro anynet_ntoa(&clt_addr)); 251490792Sgshapiro#if NETINET6 251571345Sgshapiro if (hp != NULL) 251671345Sgshapiro freehostent(hp); 251790792Sgshapiro#endif /* NETINET6 */ 251864562Sgshapiro errno = save_errno; 251964562Sgshapiro return EX_TEMPFAIL; 252064562Sgshapiro } 252164562Sgshapiro } 252264562Sgshapiro 252338032Speter /* 252438032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 252538032Speter ** Time out the connect to avoid this problem. 252638032Speter */ 252738032Speter 252838032Speter if (setjmp(CtxConnectTimeout) == 0) 252938032Speter { 253038032Speter int i; 253138032Speter 253238032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 253390792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 253490792Sgshapiro connecttimeout, 0); 253538032Speter else if (TimeOuts.to_connect != 0) 253690792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 253790792Sgshapiro connecttimeout, 0); 253838032Speter else 253938032Speter ev = NULL; 254038032Speter 254164562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 254264562Sgshapiro { 254390792Sgshapiro#if NETINET 254464562Sgshapiro case AF_INET: 254564562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 254664562Sgshapiro break; 254790792Sgshapiro#endif /* NETINET */ 254864562Sgshapiro 254990792Sgshapiro#if NETINET6 255064562Sgshapiro case AF_INET6: 255164562Sgshapiro memmove(&addr.sin6.sin6_addr, 255264562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 255364562Sgshapiro IN6ADDRSZ); 255464562Sgshapiro break; 255590792Sgshapiro#endif /* NETINET6 */ 255664562Sgshapiro } 255738032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 255864562Sgshapiro save_errno = errno; 255938032Speter if (ev != NULL) 256090792Sgshapiro sm_clrevent(ev); 256138032Speter if (i >= 0) 256238032Speter break; 256338032Speter } 256438032Speter else 256564562Sgshapiro save_errno = errno; 256638032Speter 256794334Sgshapiro /* couldn't connect.... figure out why */ 256894334Sgshapiro (void) close(s); 256994334Sgshapiro 257038032Speter /* if running demand-dialed connection, try again */ 257190792Sgshapiro if (DialDelay > 0 && firstconnect && 257290792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 257338032Speter { 257438032Speter if (tTd(16, 1)) 257590792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 257690792Sgshapiro sm_errstring(save_errno)); 257790792Sgshapiro firstconnect = false; 257864562Sgshapiro (void) sleep(DialDelay); 257938032Speter continue; 258038032Speter } 258138032Speter 258290792Sgshapiro if (LogLevel > 13) 258338032Speter sm_syslog(LOG_INFO, e->e_id, 258438032Speter "makeconnection (%s [%s]) failed: %s", 258538032Speter host, anynet_ntoa(&addr), 258690792Sgshapiro sm_errstring(save_errno)); 258738032Speter 258890792Sgshapiro#if NETINET6 258990792Sgshapironextaddr: 259090792Sgshapiro#endif /* NETINET6 */ 259190792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 259290792Sgshapiro (enough == 0 || curtime() < enough)) 259338032Speter { 259438032Speter if (tTd(16, 1)) 259590792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 259690792Sgshapiro sm_errstring(save_errno)); 259738032Speter switch (addr.sa.sa_family) 259838032Speter { 259990792Sgshapiro#if NETINET 260038032Speter case AF_INET: 260164562Sgshapiro memmove(&addr.sin.sin_addr, 260264562Sgshapiro hp->h_addr_list[addrno++], 260364562Sgshapiro INADDRSZ); 260438032Speter break; 260590792Sgshapiro#endif /* NETINET */ 260638032Speter 260790792Sgshapiro#if NETINET6 260864562Sgshapiro case AF_INET6: 260964562Sgshapiro memmove(&addr.sin6.sin6_addr, 261064562Sgshapiro hp->h_addr_list[addrno++], 261164562Sgshapiro IN6ADDRSZ); 261264562Sgshapiro break; 261390792Sgshapiro#endif /* NETINET6 */ 261464562Sgshapiro 261538032Speter default: 261664562Sgshapiro memmove(addr.sa.sa_data, 261764562Sgshapiro hp->h_addr_list[addrno++], 261838032Speter hp->h_length); 261938032Speter break; 262038032Speter } 262138032Speter continue; 262238032Speter } 262364562Sgshapiro errno = save_errno; 262438032Speter 262590792Sgshapiro#if NETINET6 262664562Sgshapiro if (family == AF_INET6) 262764562Sgshapiro { 262864562Sgshapiro if (tTd(16, 1)) 262990792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 263090792Sgshapiro sm_errstring(save_errno)); 263190792Sgshapiro v6found = true; 263264562Sgshapiro family = AF_INET; 263371345Sgshapiro if (hp != NULL) 263471345Sgshapiro { 263571345Sgshapiro freehostent(hp); 263671345Sgshapiro hp = NULL; 263771345Sgshapiro } 263864562Sgshapiro goto v4retry; 263964562Sgshapiro } 264064562Sgshapiro v6tempfail: 264190792Sgshapiro#endif /* NETINET6 */ 264238032Speter /* couldn't open connection */ 264390792Sgshapiro#if NETINET6 264464562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 264564562Sgshapiro if (errno > 0) 264690792Sgshapiro#endif /* NETINET6 */ 264764562Sgshapiro save_errno = errno; 264864562Sgshapiro if (tTd(16, 1)) 264990792Sgshapiro sm_dprintf("Connect failed (%s)\n", 265090792Sgshapiro sm_errstring(save_errno)); 265190792Sgshapiro#if XLA 265238032Speter xla_host_end(host); 265390792Sgshapiro#endif /* XLA */ 265438032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 265590792Sgshapiro#if NETINET6 265671345Sgshapiro if (hp != NULL) 265771345Sgshapiro freehostent(hp); 265890792Sgshapiro#endif /* NETINET6 */ 265964562Sgshapiro errno = save_errno; 266038032Speter return EX_TEMPFAIL; 266138032Speter } 266238032Speter 266390792Sgshapiro#if NETINET6 266471345Sgshapiro if (hp != NULL) 266571345Sgshapiro { 266671345Sgshapiro freehostent(hp); 266771345Sgshapiro hp = NULL; 266871345Sgshapiro } 266990792Sgshapiro#endif /* NETINET6 */ 267071345Sgshapiro 267138032Speter /* connection ok, put it into canonical form */ 267264562Sgshapiro mci->mci_out = NULL; 267390792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 267490792Sgshapiro (void *) &s, 267590792Sgshapiro SM_IO_WRONLY, NULL)) == NULL || 267638032Speter (s = dup(s)) < 0 || 267790792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 267890792Sgshapiro (void *) &s, 267990792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 268038032Speter { 268164562Sgshapiro save_errno = errno; 268238032Speter syserr("cannot open SMTP client channel, fd=%d", s); 268338032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 268464562Sgshapiro if (mci->mci_out != NULL) 268590792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 268664562Sgshapiro (void) close(s); 268764562Sgshapiro errno = save_errno; 268838032Speter return EX_TEMPFAIL; 268938032Speter } 269090792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 269138032Speter 269290792Sgshapiro /* set {client_flags} */ 269390792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 269490792Sgshapiro { 269590792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 269690792Sgshapiro macid("{client_flags}"), 269790792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 269890792Sgshapiro } 269990792Sgshapiro else 270090792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 270190792Sgshapiro macid("{client_flags}"), ""); 270290792Sgshapiro 270390792Sgshapiro /* "add" {client_flags} to bitmap */ 270490792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 270590792Sgshapiro { 270690792Sgshapiro /* look for just this one flag */ 270790792Sgshapiro setbitn(D_IFNHELO, d_flags); 270890792Sgshapiro } 270990792Sgshapiro 271064562Sgshapiro /* find out name for Interface through which we connect */ 271164562Sgshapiro len = sizeof addr; 271264562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 271364562Sgshapiro { 271464562Sgshapiro char *name; 271590792Sgshapiro char family[5]; 271664562Sgshapiro 271790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 271890792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 271990792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 272090792Sgshapiro addr.sa.sa_family); 272190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 272290792Sgshapiro macid("{if_family_out}"), family); 272364562Sgshapiro 272464562Sgshapiro name = hostnamebyanyaddr(&addr); 272590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 272690792Sgshapiro macid("{if_name_out}"), name); 272764562Sgshapiro if (LogLevel > 11) 272864562Sgshapiro { 272964562Sgshapiro /* log connection information */ 273064562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 273164562Sgshapiro "SMTP outgoing connect on %.40s", name); 273264562Sgshapiro } 273364562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 273464562Sgshapiro { 273564562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 273664562Sgshapiro mci->mci_heloname = newstr(name); 273764562Sgshapiro } 273864562Sgshapiro } 273964562Sgshapiro else 274064562Sgshapiro { 274190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 274290792Sgshapiro macid("{if_name_out}"), NULL); 274390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 274490792Sgshapiro macid("{if_addr_out}"), NULL); 274590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 274690792Sgshapiro macid("{if_family_out}"), NULL); 274764562Sgshapiro } 274838032Speter mci_setstat(mci, EX_OK, NULL, NULL); 274964562Sgshapiro return EX_OK; 275038032Speter} 275164562Sgshapiro 275264562Sgshapirostatic void 275364562Sgshapiroconnecttimeout() 275464562Sgshapiro{ 275577349Sgshapiro /* 275677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 275777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 275877349Sgshapiro ** DOING. 275977349Sgshapiro */ 276077349Sgshapiro 276164562Sgshapiro errno = ETIMEDOUT; 276264562Sgshapiro longjmp(CtxConnectTimeout, 1); 276364562Sgshapiro} 276490792Sgshapiro/* 276564562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 276664562Sgshapiro** 276764562Sgshapiro** Parameters: 276864562Sgshapiro** mux_path -- the path of the socket to connect to. 276964562Sgshapiro** mci -- a pointer to the mail connection information 277064562Sgshapiro** structure to be filled in. 277164562Sgshapiro** 277264562Sgshapiro** Returns: 277364562Sgshapiro** An exit code telling whether the connection could be 277464562Sgshapiro** made and if not why not. 277564562Sgshapiro** 277664562Sgshapiro** Side Effects: 277764562Sgshapiro** none. 277864562Sgshapiro*/ 277964562Sgshapiro 278090792Sgshapiro#if NETUNIX 278190792Sgshapiroint 278290792Sgshapiromakeconnection_ds(mux_path, mci) 278364562Sgshapiro char *mux_path; 278464562Sgshapiro register MCI *mci; 278564562Sgshapiro{ 278664562Sgshapiro int sock; 278764562Sgshapiro int rval, save_errno; 278864562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 278964562Sgshapiro struct sockaddr_un unix_addr; 279064562Sgshapiro 279164562Sgshapiro /* if not safe, don't connect */ 279264562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 279364562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 279464562Sgshapiro 279564562Sgshapiro if (rval != 0) 279664562Sgshapiro { 279764562Sgshapiro syserr("makeconnection_ds: unsafe domain socket"); 279864562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 279964562Sgshapiro errno = rval; 280064562Sgshapiro return EX_TEMPFAIL; 280164562Sgshapiro } 280264562Sgshapiro 280364562Sgshapiro /* prepare address structure */ 280464562Sgshapiro memset(&unix_addr, '\0', sizeof unix_addr); 280564562Sgshapiro unix_addr.sun_family = AF_UNIX; 280664562Sgshapiro 280764562Sgshapiro if (strlen(mux_path) >= sizeof unix_addr.sun_path) 280864562Sgshapiro { 280964562Sgshapiro syserr("makeconnection_ds: domain socket name too long"); 281090792Sgshapiro 281190792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 281264562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 281364562Sgshapiro errno = ENAMETOOLONG; 281464562Sgshapiro return EX_UNAVAILABLE; 281564562Sgshapiro } 281690792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 281790792Sgshapiro sizeof unix_addr.sun_path); 281864562Sgshapiro 281964562Sgshapiro /* initialize domain socket */ 282064562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 282164562Sgshapiro if (sock == -1) 282264562Sgshapiro { 282364562Sgshapiro save_errno = errno; 282464562Sgshapiro syserr("makeconnection_ds: could not create domain socket"); 282564562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 282664562Sgshapiro errno = save_errno; 282764562Sgshapiro return EX_TEMPFAIL; 282864562Sgshapiro } 282964562Sgshapiro 283064562Sgshapiro /* connect to server */ 283164562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 283264562Sgshapiro sizeof(unix_addr)) == -1) 283364562Sgshapiro { 283464562Sgshapiro save_errno = errno; 283564562Sgshapiro syserr("Could not connect to socket %s", mux_path); 283664562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 283764562Sgshapiro (void) close(sock); 283864562Sgshapiro errno = save_errno; 283964562Sgshapiro return EX_TEMPFAIL; 284064562Sgshapiro } 284164562Sgshapiro 284264562Sgshapiro /* connection ok, put it into canonical form */ 284364562Sgshapiro mci->mci_out = NULL; 284490792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 284590792Sgshapiro (void *) &sock, SM_IO_WRONLY, NULL)) 284690792Sgshapiro == NULL 284790792Sgshapiro || (sock = dup(sock)) < 0 || 284890792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 284990792Sgshapiro (void *) &sock, SM_IO_RDONLY, NULL)) 285090792Sgshapiro == NULL) 285164562Sgshapiro { 285264562Sgshapiro save_errno = errno; 285364562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 285464562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 285564562Sgshapiro if (mci->mci_out != NULL) 285690792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 285764562Sgshapiro (void) close(sock); 285864562Sgshapiro errno = save_errno; 285964562Sgshapiro return EX_TEMPFAIL; 286064562Sgshapiro } 286190792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 286264562Sgshapiro 286364562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 286464562Sgshapiro errno = 0; 286564562Sgshapiro return EX_OK; 286664562Sgshapiro} 286790792Sgshapiro#endif /* NETUNIX */ 286890792Sgshapiro/* 286990792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 287077349Sgshapiro** 287177349Sgshapiro** Parameters: 287290792Sgshapiro** none. 287377349Sgshapiro** 287477349Sgshapiro** Returns: 287577349Sgshapiro** none. 287677349Sgshapiro** 287777349Sgshapiro** Side Effects: 287890792Sgshapiro** closes control socket, exits. 287977349Sgshapiro*/ 288077349Sgshapiro 288190792Sgshapirovoid 288290792Sgshapiroshutdown_daemon() 288377349Sgshapiro{ 288490792Sgshapiro int i; 288590792Sgshapiro char *reason; 288677349Sgshapiro 288790792Sgshapiro sm_allsignals(true); 288890792Sgshapiro 288990792Sgshapiro reason = ShutdownRequest; 289090792Sgshapiro ShutdownRequest = NULL; 289190792Sgshapiro PendingSignal = 0; 289290792Sgshapiro 289390792Sgshapiro if (LogLevel > 79) 289490792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)", 289590792Sgshapiro reason == NULL ? "implicit call" : reason); 289690792Sgshapiro 289790792Sgshapiro FileName = NULL; 289890792Sgshapiro closecontrolsocket(true); 289990792Sgshapiro#if XLA 290090792Sgshapiro xla_all_end(); 290190792Sgshapiro#endif /* XLA */ 290290792Sgshapiro 290390792Sgshapiro for (i = 0; i < NDaemons; i++) 290490792Sgshapiro { 290590792Sgshapiro if (Daemons[i].d_socket >= 0) 290690792Sgshapiro { 290790792Sgshapiro (void) close(Daemons[i].d_socket); 290890792Sgshapiro Daemons[i].d_socket = -1; 290990792Sgshapiro 291090792Sgshapiro#if _FFR_DAEMON_NETUNIX 291190792Sgshapiro# if NETUNIX 291290792Sgshapiro /* Remove named sockets */ 291390792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 291490792Sgshapiro { 291590792Sgshapiro int rval; 291690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 291790792Sgshapiro 291890792Sgshapiro /* if not safe, don't use it */ 291990792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 292090792Sgshapiro RunAsUid, RunAsGid, 292190792Sgshapiro RunAsUserName, sff, 292290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 292390792Sgshapiro if (rval == 0 && 292490792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 292590792Sgshapiro { 292690792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 292790792Sgshapiro "Could not remove daemon %s socket: %s: %s", 292890792Sgshapiro Daemons[i].d_name, 292990792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 293090792Sgshapiro sm_errstring(errno)); 293190792Sgshapiro } 293290792Sgshapiro } 293390792Sgshapiro# endif /* NETUNIX */ 293490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 293590792Sgshapiro } 293690792Sgshapiro } 293790792Sgshapiro 293890792Sgshapiro finis(false, true, EX_OK); 293977349Sgshapiro} 294090792Sgshapiro/* 294177349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 294277349Sgshapiro** 294377349Sgshapiro** Parameters: 294477349Sgshapiro** none. 294577349Sgshapiro** 294677349Sgshapiro** Returns: 294777349Sgshapiro** none. 294877349Sgshapiro** 294977349Sgshapiro** Side Effects: 295077349Sgshapiro** restarts the daemon or exits if restart fails. 295177349Sgshapiro*/ 295277349Sgshapiro 295380785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 295480785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 295580785Sgshapirodo \ 295680785Sgshapiro{ \ 295790792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 295880785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 295990792Sgshapiro (void) sm_signal((sig), (old)); \ 296080785Sgshapiro} while (0) 296180785Sgshapiro 296290792Sgshapirovoid 296377349Sgshapirorestart_daemon() 296477349Sgshapiro{ 296590792Sgshapiro bool drop; 296677349Sgshapiro int i; 296777349Sgshapiro int save_errno; 296877349Sgshapiro char *reason; 296980785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 297077349Sgshapiro extern int DtableSize; 297177349Sgshapiro 297280785Sgshapiro /* clear the events to turn off SIGALRMs */ 297390792Sgshapiro sm_clear_events(); 297490792Sgshapiro sm_allsignals(true); 297577349Sgshapiro 297677349Sgshapiro reason = RestartRequest; 297777349Sgshapiro RestartRequest = NULL; 297877349Sgshapiro PendingSignal = 0; 297977349Sgshapiro 298077349Sgshapiro if (SaveArgv[0][0] != '/') 298177349Sgshapiro { 298277349Sgshapiro if (LogLevel > 3) 298377349Sgshapiro sm_syslog(LOG_INFO, NOQID, 298477349Sgshapiro "could not restart: need full path"); 298590792Sgshapiro finis(false, true, EX_OSFILE); 298690792Sgshapiro /* NOTREACHED */ 298777349Sgshapiro } 298877349Sgshapiro if (LogLevel > 3) 298977349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 299077349Sgshapiro SaveArgv[0], 299177349Sgshapiro reason == NULL ? "implicit call" : reason); 299277349Sgshapiro 299390792Sgshapiro closecontrolsocket(true); 299498121Sgshapiro#if SM_CONF_SHM 299598121Sgshapiro cleanup_shm(DaemonPid == getpid()); 299698121Sgshapiro#endif /* SM_CONF_SHM */ 299790792Sgshapiro 299890792Sgshapiro /* 299990792Sgshapiro ** Want to drop to the user who started the process in all cases 300090792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 300190792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 300290792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 300390792Sgshapiro */ 300490792Sgshapiro 300590792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 300690792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 300790792Sgshapiro 300890792Sgshapiro if (drop_privileges(drop) != EX_OK) 300977349Sgshapiro { 301077349Sgshapiro if (LogLevel > 0) 301177349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 301290792Sgshapiro "could not drop privileges: %s", 301390792Sgshapiro sm_errstring(errno)); 301490792Sgshapiro finis(false, true, EX_OSERR); 301590792Sgshapiro /* NOTREACHED */ 301677349Sgshapiro } 301777349Sgshapiro 301877349Sgshapiro /* arrange for all the files to be closed */ 301977349Sgshapiro for (i = 3; i < DtableSize; i++) 302077349Sgshapiro { 302177349Sgshapiro register int j; 302277349Sgshapiro 302377349Sgshapiro if ((j = fcntl(i, F_GETFD, 0)) != -1) 302477349Sgshapiro (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); 302577349Sgshapiro } 302677349Sgshapiro 302780785Sgshapiro /* 302880785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 302980785Sgshapiro ** However, the default action can be "terminate", so it isn't 303080785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 303180785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 303280785Sgshapiro */ 303380785Sgshapiro 303480785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 303580785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 303680785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 303780785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 303880785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 303980785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 304080785Sgshapiro#ifdef SIGUSR1 304180785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 304280785Sgshapiro#endif /* SIGUSR1 */ 304394334Sgshapiro 304494334Sgshapiro /* Turn back on signals */ 304590792Sgshapiro sm_allsignals(false); 304677349Sgshapiro 304777349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 304877349Sgshapiro save_errno = errno; 304977349Sgshapiro 305080785Sgshapiro /* block signals again and restore needed signals */ 305190792Sgshapiro sm_allsignals(true); 305280785Sgshapiro 305380785Sgshapiro /* For finis() events */ 305490792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 305580785Sgshapiro 305680785Sgshapiro#ifdef SIGUSR1 305780785Sgshapiro /* For debugging finis() */ 305890792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 305980785Sgshapiro#endif /* SIGUSR1 */ 306077349Sgshapiro 306177349Sgshapiro errno = save_errno; 306277349Sgshapiro if (LogLevel > 0) 306390792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 306490792Sgshapiro SaveArgv[0], sm_errstring(errno)); 306590792Sgshapiro finis(false, true, EX_OSFILE); 306690792Sgshapiro /* NOTREACHED */ 306777349Sgshapiro} 306890792Sgshapiro/* 306938032Speter** MYHOSTNAME -- return the name of this host. 307038032Speter** 307138032Speter** Parameters: 307238032Speter** hostbuf -- a place to return the name of this host. 307338032Speter** size -- the size of hostbuf. 307438032Speter** 307538032Speter** Returns: 307638032Speter** A list of aliases for this host. 307738032Speter** 307838032Speter** Side Effects: 307938032Speter** Adds numeric codes to $=w. 308038032Speter*/ 308138032Speter 308238032Speterstruct hostent * 308338032Spetermyhostname(hostbuf, size) 308438032Speter char hostbuf[]; 308538032Speter int size; 308638032Speter{ 308738032Speter register struct hostent *hp; 308838032Speter 308973188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 309090792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 309164562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 309290792Sgshapiro#if NETINET && NETINET6 309380785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 309480785Sgshapiro { 309580785Sgshapiro /* 309680785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 309780785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 309880785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 309980785Sgshapiro */ 310080785Sgshapiro 310180785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 310280785Sgshapiro } 310390792Sgshapiro#endif /* NETINET && NETINET6 */ 310438032Speter if (hp == NULL) 310538032Speter return NULL; 310638032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 310764562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 310864562Sgshapiro 310990792Sgshapiro#if NETINFO 311064562Sgshapiro if (strchr(hostbuf, '.') == NULL) 311138032Speter { 311264562Sgshapiro char *domainname; 311364562Sgshapiro 311464562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 311564562Sgshapiro "domain", '\0'); 311664562Sgshapiro if (domainname != NULL && 311764562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 311890792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 311938032Speter } 312090792Sgshapiro#endif /* NETINFO */ 312138032Speter 312238032Speter /* 312338032Speter ** If there is still no dot in the name, try looking for a 312438032Speter ** dotted alias. 312538032Speter */ 312638032Speter 312738032Speter if (strchr(hostbuf, '.') == NULL) 312838032Speter { 312938032Speter char **ha; 313038032Speter 313164562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 313238032Speter { 313338032Speter if (strchr(*ha, '.') != NULL) 313438032Speter { 313564562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 313638032Speter hostbuf[size - 1] = '\0'; 313738032Speter break; 313838032Speter } 313938032Speter } 314038032Speter } 314138032Speter 314238032Speter /* 314338032Speter ** If _still_ no dot, wait for a while and try again -- it is 314438032Speter ** possible that some service is starting up. This can result 314538032Speter ** in excessive delays if the system is badly configured, but 314638032Speter ** there really isn't a way around that, particularly given that 314738032Speter ** the config file hasn't been read at this point. 314838032Speter ** All in all, a bit of a mess. 314938032Speter */ 315038032Speter 315138032Speter if (strchr(hostbuf, '.') == NULL && 315290792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 315338032Speter { 315438032Speter sm_syslog(LOG_CRIT, NOQID, 315564562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 315664562Sgshapiro hostbuf); 315738032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 315838032Speter hostbuf); 315964562Sgshapiro (void) sleep(60); 316090792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 316138032Speter { 316238032Speter sm_syslog(LOG_ALERT, NOQID, 316364562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 316464562Sgshapiro hostbuf); 316538032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 316638032Speter hostbuf); 316738032Speter } 316838032Speter } 316964562Sgshapiro return hp; 317038032Speter} 317190792Sgshapiro/* 317238032Speter** ADDRCMP -- compare two host addresses 317338032Speter** 317438032Speter** Parameters: 317538032Speter** hp -- hostent structure for the first address 317638032Speter** ha -- actual first address 317738032Speter** sa -- second address 317838032Speter** 317938032Speter** Returns: 318038032Speter** 0 -- if ha and sa match 318138032Speter** else -- they don't match 318238032Speter*/ 318338032Speter 318464562Sgshapirostatic int 318538032Speteraddrcmp(hp, ha, sa) 318638032Speter struct hostent *hp; 318738032Speter char *ha; 318838032Speter SOCKADDR *sa; 318938032Speter{ 319090792Sgshapiro#if NETINET6 319190792Sgshapiro unsigned char *a; 319290792Sgshapiro#endif /* NETINET6 */ 319364562Sgshapiro 319438032Speter switch (sa->sa.sa_family) 319538032Speter { 319690792Sgshapiro#if NETINET 319738032Speter case AF_INET: 319838032Speter if (hp->h_addrtype == AF_INET) 319964562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 320038032Speter break; 320190792Sgshapiro#endif /* NETINET */ 320238032Speter 320390792Sgshapiro#if NETINET6 320464562Sgshapiro case AF_INET6: 320590792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 320664562Sgshapiro 320764562Sgshapiro /* Straight binary comparison */ 320864562Sgshapiro if (hp->h_addrtype == AF_INET6) 320964562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 321064562Sgshapiro 321164562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 321264562Sgshapiro if (hp->h_addrtype == AF_INET && 321364562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 321464562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 321564562Sgshapiro break; 321690792Sgshapiro#endif /* NETINET6 */ 321738032Speter } 321838032Speter return -1; 321938032Speter} 322090792Sgshapiro/* 322164562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 322238032Speter** 322338032Speter** Uses RFC1413 protocol to try to get info from the other end. 322438032Speter** 322538032Speter** Parameters: 322638032Speter** fd -- the descriptor 322790792Sgshapiro** may_be_forged -- an outage that is set to true if the 322838032Speter** forward lookup of RealHostName does not match 322990792Sgshapiro** RealHostAddr; set to false if they do match. 323038032Speter** 323138032Speter** Returns: 323238032Speter** The user@host information associated with this descriptor. 323338032Speter*/ 323438032Speter 323538032Speterstatic jmp_buf CtxAuthTimeout; 323638032Speter 323738032Speterstatic void 323838032Speterauthtimeout() 323938032Speter{ 324077349Sgshapiro /* 324177349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 324277349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 324377349Sgshapiro ** DOING. 324477349Sgshapiro */ 324577349Sgshapiro 324677349Sgshapiro errno = ETIMEDOUT; 324738032Speter longjmp(CtxAuthTimeout, 1); 324838032Speter} 324938032Speter 325038032Speterchar * 325138032Spetergetauthinfo(fd, may_be_forged) 325238032Speter int fd; 325338032Speter bool *may_be_forged; 325438032Speter{ 325590792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 325638032Speter SOCKADDR_LEN_T falen; 325738032Speter register char *volatile p = NULL; 325838032Speter SOCKADDR la; 325938032Speter SOCKADDR_LEN_T lalen; 326090792Sgshapiro#ifndef NO_GETSERVBYNAME 326138032Speter register struct servent *sp; 326290792Sgshapiro# if NETINET 326390792Sgshapiro static unsigned short port4 = 0; 326490792Sgshapiro# endif /* NETINET */ 326590792Sgshapiro# if NETINET6 326690792Sgshapiro static unsigned short port6 = 0; 326790792Sgshapiro# endif /* NETINET6 */ 326890792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 326938032Speter volatile int s; 327038032Speter int i = 0; 327190792Sgshapiro size_t len; 327290792Sgshapiro SM_EVENT *ev; 327338032Speter int nleft; 327438032Speter struct hostent *hp; 327538032Speter char *ostype = NULL; 327638032Speter char **ha; 327738032Speter char ibuf[MAXNAME + 1]; 3278110560Sgshapiro static char hbuf[MAXNAME + MAXAUTHINFO + 11]; 327938032Speter 328090792Sgshapiro *may_be_forged = false; 328138032Speter falen = sizeof RealHostAddr; 328238032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 328338032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 328438032Speter { 328564562Sgshapiro if (i < 0) 328664562Sgshapiro { 328764562Sgshapiro /* 328864562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 328964562Sgshapiro ** errno in this case, so a mis-report doesn't 329064562Sgshapiro ** happen later. 329164562Sgshapiro */ 329290792Sgshapiro 329364562Sgshapiro if (errno != ENOTSOCK) 329464562Sgshapiro return NULL; 329564562Sgshapiro errno = 0; 329664562Sgshapiro } 329790792Sgshapiro (void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName, 329890792Sgshapiro "@localhost"); 329938032Speter if (tTd(9, 1)) 330090792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 330138032Speter return hbuf; 330238032Speter } 330338032Speter 330438032Speter if (RealHostName == NULL) 330538032Speter { 330638032Speter /* translate that to a host name */ 330738032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 330838032Speter if (strlen(RealHostName) > MAXNAME) 330990792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 331038032Speter } 331138032Speter 331238032Speter /* cross check RealHostName with forward DNS lookup */ 331390792Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] != '[' && 331490792Sgshapiro RealHostName[0] != '[') 331538032Speter { 331680785Sgshapiro int family; 331780785Sgshapiro 331880785Sgshapiro family = RealHostAddr.sa.sa_family; 331990792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 332080785Sgshapiro /* 332180785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 332280785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 332380785Sgshapiro ** address(es) for addrcmp() to compare against 332480785Sgshapiro ** RealHostAddr. 332580785Sgshapiro ** 332680785Sgshapiro ** Actually, we only need to do this for systems 332780785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 332880785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 332980785Sgshapiro ** flag. A better fix to this problem is to add this 333080785Sgshapiro ** functionality to our stub getipnodebyname(). 333180785Sgshapiro */ 333280785Sgshapiro 333380785Sgshapiro if (family == AF_INET6 && 333480785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 333580785Sgshapiro family = AF_INET; 333690792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 333780785Sgshapiro 333838032Speter /* try to match the reverse against the forward lookup */ 333980785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 334038032Speter if (hp == NULL) 3341120256Sgshapiro { 334290792Sgshapiro *may_be_forged = true; 3343120256Sgshapiro } 334438032Speter else 334538032Speter { 334638032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 334790792Sgshapiro { 334838032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 334938032Speter break; 335090792Sgshapiro } 335138032Speter *may_be_forged = *ha == NULL; 335290792Sgshapiro#if NETINET6 335371345Sgshapiro freehostent(hp); 335471345Sgshapiro hp = NULL; 335590792Sgshapiro#endif /* NETINET6 */ 335638032Speter } 335738032Speter } 335838032Speter 335938032Speter if (TimeOuts.to_ident == 0) 336038032Speter goto noident; 336138032Speter 336238032Speter lalen = sizeof la; 336364562Sgshapiro switch (RealHostAddr.sa.sa_family) 336438032Speter { 336590792Sgshapiro#if NETINET 336664562Sgshapiro case AF_INET: 336764562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 336864562Sgshapiro lalen <= 0 || 336964562Sgshapiro la.sa.sa_family != AF_INET) 337064562Sgshapiro { 337164562Sgshapiro /* no ident info */ 337264562Sgshapiro goto noident; 337364562Sgshapiro } 337464562Sgshapiro port = RealHostAddr.sin.sin_port; 337538032Speter 337664562Sgshapiro /* create ident query */ 337790792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 337864562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 337964562Sgshapiro ntohs(la.sin.sin_port)); 338038032Speter 338164562Sgshapiro /* create local address */ 338264562Sgshapiro la.sin.sin_port = 0; 338338032Speter 338464562Sgshapiro /* create foreign address */ 338590792Sgshapiro# ifdef NO_GETSERVBYNAME 338638032Speter RealHostAddr.sin.sin_port = htons(113); 338790792Sgshapiro# else /* NO_GETSERVBYNAME */ 338890792Sgshapiro 338990792Sgshapiro /* 339090792Sgshapiro ** getservbyname() consumes about 5% of the time 339190792Sgshapiro ** when receiving a small message (almost all of the time 339290792Sgshapiro ** spent in this routine). 339390792Sgshapiro ** Hence we store the port in a static variable 339490792Sgshapiro ** to save this time. 339590792Sgshapiro ** The portnumber shouldn't change very often... 339690792Sgshapiro ** This code makes the assumption that the port number 339790792Sgshapiro ** is not 0. 339890792Sgshapiro */ 339990792Sgshapiro 340090792Sgshapiro if (port4 == 0) 340190792Sgshapiro { 340290792Sgshapiro sp = getservbyname("auth", "tcp"); 340390792Sgshapiro if (sp != NULL) 340490792Sgshapiro port4 = sp->s_port; 340590792Sgshapiro else 340690792Sgshapiro port4 = htons(113); 340790792Sgshapiro } 340890792Sgshapiro RealHostAddr.sin.sin_port = port4; 340964562Sgshapiro break; 341090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 341190792Sgshapiro#endif /* NETINET */ 341238032Speter 341390792Sgshapiro#if NETINET6 341464562Sgshapiro case AF_INET6: 341564562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 341664562Sgshapiro lalen <= 0 || 341764562Sgshapiro la.sa.sa_family != AF_INET6) 341864562Sgshapiro { 341964562Sgshapiro /* no ident info */ 342064562Sgshapiro goto noident; 342164562Sgshapiro } 342264562Sgshapiro port = RealHostAddr.sin6.sin6_port; 342364562Sgshapiro 342464562Sgshapiro /* create ident query */ 342590792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 342664562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 342764562Sgshapiro ntohs(la.sin6.sin6_port)); 342864562Sgshapiro 342964562Sgshapiro /* create local address */ 343064562Sgshapiro la.sin6.sin6_port = 0; 343164562Sgshapiro 343264562Sgshapiro /* create foreign address */ 343390792Sgshapiro# ifdef NO_GETSERVBYNAME 343464562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 343590792Sgshapiro# else /* NO_GETSERVBYNAME */ 343690792Sgshapiro if (port6 == 0) 343790792Sgshapiro { 343890792Sgshapiro sp = getservbyname("auth", "tcp"); 343990792Sgshapiro if (sp != NULL) 344090792Sgshapiro port6 = sp->s_port; 344190792Sgshapiro else 344290792Sgshapiro port6 = htons(113); 344390792Sgshapiro } 344490792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 344564562Sgshapiro break; 344690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 344790792Sgshapiro#endif /* NETINET6 */ 344864562Sgshapiro default: 344964562Sgshapiro /* no ident info */ 345064562Sgshapiro goto noident; 345164562Sgshapiro } 345264562Sgshapiro 345338032Speter s = -1; 345438032Speter if (setjmp(CtxAuthTimeout) != 0) 345538032Speter { 345638032Speter if (s >= 0) 345738032Speter (void) close(s); 345838032Speter goto noident; 345938032Speter } 346038032Speter 346138032Speter /* put a timeout around the whole thing */ 346290792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 346338032Speter 346438032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 346564562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 346638032Speter if (s < 0) 346738032Speter { 346890792Sgshapiro sm_clrevent(ev); 346938032Speter goto noident; 347038032Speter } 347164562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 347264562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 347338032Speter goto closeident; 347438032Speter 347538032Speter if (tTd(9, 10)) 347690792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 347738032Speter 347838032Speter /* send query */ 347938032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 348038032Speter goto closeident; 348138032Speter 348238032Speter /* get result */ 348338032Speter p = &ibuf[0]; 348438032Speter nleft = sizeof ibuf - 1; 348538032Speter while ((i = read(s, p, nleft)) > 0) 348638032Speter { 348738032Speter p += i; 348838032Speter nleft -= i; 348938032Speter *p = '\0'; 349090792Sgshapiro if (strchr(ibuf, '\n') != NULL || nleft <= 0) 349138032Speter break; 349238032Speter } 349338032Speter (void) close(s); 349490792Sgshapiro sm_clrevent(ev); 349538032Speter if (i < 0 || p == &ibuf[0]) 349638032Speter goto noident; 349738032Speter 3498111823Sgshapiro if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r') 349938032Speter p--; 350038032Speter *++p = '\0'; 350138032Speter 350238032Speter if (tTd(9, 3)) 350390792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 350438032Speter 350538032Speter /* parse result */ 350638032Speter p = strchr(ibuf, ':'); 350738032Speter if (p == NULL) 350838032Speter { 350938032Speter /* malformed response */ 351038032Speter goto noident; 351138032Speter } 351238032Speter while (isascii(*++p) && isspace(*p)) 351338032Speter continue; 351490792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 351538032Speter { 351638032Speter /* presumably an error string */ 351738032Speter goto noident; 351838032Speter } 351938032Speter p += 6; 352038032Speter while (isascii(*p) && isspace(*p)) 352138032Speter p++; 352238032Speter if (*p++ != ':') 352338032Speter { 352438032Speter /* either useridxx or malformed response */ 352538032Speter goto noident; 352638032Speter } 352738032Speter 352838032Speter /* p now points to the OSTYPE field */ 352938032Speter while (isascii(*p) && isspace(*p)) 353038032Speter p++; 353138032Speter ostype = p; 353238032Speter p = strchr(p, ':'); 353338032Speter if (p == NULL) 353438032Speter { 353538032Speter /* malformed response */ 353638032Speter goto noident; 353738032Speter } 353838032Speter else 353938032Speter { 354038032Speter char *charset; 354138032Speter 354238032Speter *p = '\0'; 354338032Speter charset = strchr(ostype, ','); 354438032Speter if (charset != NULL) 354538032Speter *charset = '\0'; 354638032Speter } 354738032Speter 354838032Speter /* 1413 says don't do this -- but it's broken otherwise */ 354938032Speter while (isascii(*++p) && isspace(*p)) 355038032Speter continue; 355138032Speter 355238032Speter /* p now points to the authenticated name -- copy carefully */ 355390792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 355438032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 355538032Speter { 355690792Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf); 3557110560Sgshapiro cleanstrcpy(&hbuf[6], p, MAXAUTHINFO); 355838032Speter } 355938032Speter else 3560110560Sgshapiro cleanstrcpy(hbuf, p, MAXAUTHINFO); 356190792Sgshapiro len = strlen(hbuf); 356290792Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@", 356390792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 356438032Speter goto postident; 356538032Speter 356638032Spetercloseident: 356738032Speter (void) close(s); 356890792Sgshapiro sm_clrevent(ev); 356938032Speter 357038032Speternoident: 357164562Sgshapiro /* put back the original incoming port */ 357264562Sgshapiro switch (RealHostAddr.sa.sa_family) 357364562Sgshapiro { 357490792Sgshapiro#if NETINET 357564562Sgshapiro case AF_INET: 357664562Sgshapiro if (port > 0) 357764562Sgshapiro RealHostAddr.sin.sin_port = port; 357864562Sgshapiro break; 357990792Sgshapiro#endif /* NETINET */ 358064562Sgshapiro 358190792Sgshapiro#if NETINET6 358264562Sgshapiro case AF_INET6: 358364562Sgshapiro if (port > 0) 358464562Sgshapiro RealHostAddr.sin6.sin6_port = port; 358564562Sgshapiro break; 358690792Sgshapiro#endif /* NETINET6 */ 358764562Sgshapiro } 358864562Sgshapiro 358938032Speter if (RealHostName == NULL) 359038032Speter { 359138032Speter if (tTd(9, 1)) 359290792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 359338032Speter return NULL; 359438032Speter } 359590792Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf); 359638032Speter 359738032Speterpostident: 359890792Sgshapiro#if IP_SRCROUTE 359990792Sgshapiro# ifndef GET_IPOPT_DST 360090792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 360190792Sgshapiro# endif /* ! GET_IPOPT_DST */ 360238032Speter /* 360338032Speter ** Extract IP source routing information. 360438032Speter ** 360538032Speter ** Format of output for a connection from site a through b 360638032Speter ** through c to d: 360738032Speter ** loose: @site-c@site-b:site-a 360838032Speter ** strict: !@site-c@site-b:site-a 360938032Speter ** 361038032Speter ** o - pointer within ipopt_list structure. 361138032Speter ** q - pointer within ls/ss rr route data 361238032Speter ** p - pointer to hbuf 361338032Speter */ 361438032Speter 361538032Speter if (RealHostAddr.sa.sa_family == AF_INET) 361638032Speter { 361738032Speter SOCKOPT_LEN_T ipoptlen; 361838032Speter int j; 361990792Sgshapiro unsigned char *q; 362090792Sgshapiro unsigned char *o; 362138032Speter int l; 362264562Sgshapiro struct IPOPTION ipopt; 362338032Speter 362438032Speter ipoptlen = sizeof ipopt; 362538032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 362638032Speter (char *) &ipopt, &ipoptlen) < 0) 362738032Speter goto noipsr; 362838032Speter if (ipoptlen == 0) 362938032Speter goto noipsr; 363090792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 363190792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 363238032Speter { 363338032Speter switch (*o) 363438032Speter { 363564562Sgshapiro case IPOPT_EOL: 363638032Speter o = NULL; 363738032Speter break; 363838032Speter 363938032Speter case IPOPT_NOP: 364038032Speter o++; 364138032Speter break; 364238032Speter 364338032Speter case IPOPT_SSRR: 364438032Speter case IPOPT_LSRR: 364538032Speter /* 364638032Speter ** Source routing. 364738032Speter ** o[0] is the option type (loose/strict). 364838032Speter ** o[1] is the length of this option, 364938032Speter ** including option type and 365038032Speter ** length. 365138032Speter ** o[2] is the pointer into the route 365238032Speter ** data. 365338032Speter ** o[3] begins the route data. 365438032Speter */ 365538032Speter 365638032Speter p = &hbuf[strlen(hbuf)]; 365738032Speter l = sizeof hbuf - (hbuf - p) - 6; 365890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 365990792Sgshapiro " [%s@%.*s", 366090792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 366190792Sgshapiro l > 240 ? 120 : l / 2, 366290792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 366338032Speter i = strlen(p); 366438032Speter p += i; 366538032Speter l -= strlen(p); 366638032Speter 366738032Speter j = o[1] / sizeof(struct in_addr) - 1; 366838032Speter 366938032Speter /* q skips length and router pointer to data */ 367038032Speter q = &o[3]; 367138032Speter for ( ; j >= 0; j--) 367238032Speter { 367364562Sgshapiro struct in_addr addr; 367464562Sgshapiro 367538032Speter memcpy(&addr, q, sizeof(addr)); 367690792Sgshapiro (void) sm_snprintf(p, 367790792Sgshapiro SPACELEFT(hbuf, p), 367890792Sgshapiro "%c%.*s", 367990792Sgshapiro j != 0 ? '@' : ':', 368090792Sgshapiro l > 240 ? 120 : 368190792Sgshapiro j == 0 ? l : l / 2, 368290792Sgshapiro inet_ntoa(addr)); 368338032Speter i = strlen(p); 368438032Speter p += i; 368538032Speter l -= i + 1; 368664562Sgshapiro q += sizeof(struct in_addr); 368738032Speter } 368838032Speter o += o[1]; 368938032Speter break; 369038032Speter 369138032Speter default: 369238032Speter /* Skip over option */ 369338032Speter o += o[1]; 369438032Speter break; 369538032Speter } 369638032Speter } 369790792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 369838032Speter goto postipsr; 369938032Speter } 370038032Speter 370138032Speternoipsr: 370290792Sgshapiro#endif /* IP_SRCROUTE */ 370338032Speter if (RealHostName != NULL && RealHostName[0] != '[') 370438032Speter { 370538032Speter p = &hbuf[strlen(hbuf)]; 370690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 370790792Sgshapiro anynet_ntoa(&RealHostAddr)); 370838032Speter } 370938032Speter if (*may_be_forged) 371038032Speter { 371138032Speter p = &hbuf[strlen(hbuf)]; 371290792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 371390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 371490792Sgshapiro macid("{client_resolve}"), "FORGED"); 371538032Speter } 371638032Speter 371790792Sgshapiro#if IP_SRCROUTE 371838032Speterpostipsr: 371990792Sgshapiro#endif /* IP_SRCROUTE */ 372064562Sgshapiro 372164562Sgshapiro /* put back the original incoming port */ 372264562Sgshapiro switch (RealHostAddr.sa.sa_family) 372364562Sgshapiro { 372490792Sgshapiro#if NETINET 372564562Sgshapiro case AF_INET: 372664562Sgshapiro if (port > 0) 372764562Sgshapiro RealHostAddr.sin.sin_port = port; 372864562Sgshapiro break; 372990792Sgshapiro#endif /* NETINET */ 373064562Sgshapiro 373190792Sgshapiro#if NETINET6 373264562Sgshapiro case AF_INET6: 373364562Sgshapiro if (port > 0) 373464562Sgshapiro RealHostAddr.sin6.sin6_port = port; 373564562Sgshapiro break; 373690792Sgshapiro#endif /* NETINET6 */ 373764562Sgshapiro } 373864562Sgshapiro 373990792Sgshapiro if (tTd(9, 1)) 374090792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 374138032Speter return hbuf; 374238032Speter} 374390792Sgshapiro/* 374438032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 374538032Speter** 374638032Speter** Parameters: 374738032Speter** map -- a pointer to this map. 374838032Speter** name -- the (presumably unqualified) hostname. 374938032Speter** av -- unused -- for compatibility with other mapping 375038032Speter** functions. 375138032Speter** statp -- an exit status (out parameter) -- set to 375238032Speter** EX_TEMPFAIL if the name server is unavailable. 375338032Speter** 375438032Speter** Returns: 375538032Speter** The mapping, if found. 375638032Speter** NULL if no mapping found. 375738032Speter** 375838032Speter** Side Effects: 375938032Speter** Looks up the host specified in hbuf. If it is not 376038032Speter** the canonical name for that host, return the canonical 376138032Speter** name (unless MF_MATCHONLY is set, which will cause the 376238032Speter** status only to be returned). 376338032Speter*/ 376438032Speter 376538032Speterchar * 376638032Speterhost_map_lookup(map, name, av, statp) 376738032Speter MAP *map; 376838032Speter char *name; 376938032Speter char **av; 377038032Speter int *statp; 377138032Speter{ 377238032Speter register struct hostent *hp; 377390792Sgshapiro#if NETINET 377438032Speter struct in_addr in_addr; 377590792Sgshapiro#endif /* NETINET */ 377690792Sgshapiro#if NETINET6 377764562Sgshapiro struct in6_addr in6_addr; 377890792Sgshapiro#endif /* NETINET6 */ 377964562Sgshapiro char *cp, *ans = NULL; 378038032Speter register STAB *s; 378190792Sgshapiro time_t now; 378290792Sgshapiro#if NAMED_BIND 378390792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 378490792Sgshapiro int SM_NONVOLATILE retry = 0; 378590792Sgshapiro#endif /* NAMED_BIND */ 378638032Speter char hbuf[MAXNAME + 1]; 378738032Speter 378838032Speter /* 378938032Speter ** See if we have already looked up this name. If so, just 379090792Sgshapiro ** return it (unless expired). 379138032Speter */ 379238032Speter 379390792Sgshapiro now = curtime(); 379438032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 379590792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 379690792Sgshapiro s->s_namecanon.nc_exp >= now) 379738032Speter { 379838032Speter if (tTd(9, 1)) 379990792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 380090792Sgshapiro name, 380190792Sgshapiro s->s_namecanon.nc_cname == NULL 380238032Speter ? "NULL" 380338032Speter : s->s_namecanon.nc_cname); 380438032Speter errno = s->s_namecanon.nc_errno; 380573188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 380638032Speter *statp = s->s_namecanon.nc_stat; 380738032Speter if (*statp == EX_TEMPFAIL) 380838032Speter { 380938032Speter CurEnv->e_status = "4.4.3"; 381038032Speter message("851 %s: Name server timeout", 381138032Speter shortenstring(name, 33)); 381238032Speter } 381338032Speter if (*statp != EX_OK) 381438032Speter return NULL; 381538032Speter if (s->s_namecanon.nc_cname == NULL) 381638032Speter { 381738032Speter syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", 381864562Sgshapiro name, 381964562Sgshapiro s->s_namecanon.nc_errno, 382064562Sgshapiro s->s_namecanon.nc_herrno); 382138032Speter return NULL; 382238032Speter } 382338032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 382438032Speter cp = map_rewrite(map, name, strlen(name), NULL); 382538032Speter else 382638032Speter cp = map_rewrite(map, 382738032Speter s->s_namecanon.nc_cname, 382838032Speter strlen(s->s_namecanon.nc_cname), 382938032Speter av); 383038032Speter return cp; 383138032Speter } 383238032Speter 383338032Speter /* 383438032Speter ** If we are running without a regular network connection (usually 383538032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 383638032Speter ** lookups because those could try to connect to a server. 383738032Speter */ 383838032Speter 383964562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 384064562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 384138032Speter { 384238032Speter if (tTd(9, 1)) 384390792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 384438032Speter *statp = EX_TEMPFAIL; 384538032Speter return NULL; 384638032Speter } 384738032Speter 384838032Speter /* 384938032Speter ** If first character is a bracket, then it is an address 385038032Speter ** lookup. Address is copied into a temporary buffer to 385138032Speter ** strip the brackets and to preserve name if address is 385238032Speter ** unknown. 385338032Speter */ 385438032Speter 385564562Sgshapiro if (tTd(9, 1)) 385690792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 385790792Sgshapiro#if NAMED_BIND 385890792Sgshapiro if (map->map_timeout > 0) 385990792Sgshapiro { 386090792Sgshapiro retrans = _res.retrans; 386190792Sgshapiro _res.retrans = map->map_timeout; 386290792Sgshapiro } 386390792Sgshapiro if (map->map_retry > 0) 386490792Sgshapiro { 386590792Sgshapiro retry = _res.retry; 386690792Sgshapiro _res.retry = map->map_retry; 386790792Sgshapiro } 386890792Sgshapiro#endif /* NAMED_BIND */ 386990792Sgshapiro 387090792Sgshapiro /* set default TTL */ 387190792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 387238032Speter if (*name != '[') 387338032Speter { 387490792Sgshapiro int ttl; 387590792Sgshapiro 387690792Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof hbuf); 387790792Sgshapiro if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl)) 387890792Sgshapiro { 387964562Sgshapiro ans = hbuf; 388090792Sgshapiro if (ttl > 0) 388190792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 388290792Sgshapiro SM_DEFAULT_TTL); 388390792Sgshapiro } 388464562Sgshapiro } 388564562Sgshapiro else 388664562Sgshapiro { 388764562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 388871345Sgshapiro { 388971345Sgshapiro if (tTd(9, 1)) 389090792Sgshapiro sm_dprintf("FAILED\n"); 389164562Sgshapiro return NULL; 389271345Sgshapiro } 389364562Sgshapiro *cp = '\0'; 389464562Sgshapiro 389564562Sgshapiro hp = NULL; 389690792Sgshapiro#if NETINET 389764562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 389864562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 389964562Sgshapiro INADDRSZ, AF_INET); 390090792Sgshapiro#endif /* NETINET */ 390190792Sgshapiro#if NETINET6 390264562Sgshapiro if (hp == NULL && 390390792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 390464562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 390564562Sgshapiro IN6ADDRSZ, AF_INET6); 390690792Sgshapiro#endif /* NETINET6 */ 390764562Sgshapiro *cp = ']'; 390864562Sgshapiro 390964562Sgshapiro if (hp != NULL) 391038032Speter { 391164562Sgshapiro /* found a match -- copy out */ 391290792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 391390792Sgshapiro#if NETINET6 391490792Sgshapiro if (ans == hp->h_name) 391590792Sgshapiro { 391690792Sgshapiro static char n[MAXNAME + 1]; 391790792Sgshapiro 391890792Sgshapiro /* hp->h_name is about to disappear */ 391990792Sgshapiro (void) sm_strlcpy(n, ans, sizeof n); 392090792Sgshapiro ans = n; 392190792Sgshapiro } 392271345Sgshapiro freehostent(hp); 392371345Sgshapiro hp = NULL; 392490792Sgshapiro#endif /* NETINET6 */ 392538032Speter } 392664562Sgshapiro } 392790792Sgshapiro#if NAMED_BIND 392890792Sgshapiro if (map->map_timeout > 0) 392990792Sgshapiro _res.retrans = retrans; 393090792Sgshapiro if (map->map_retry > 0) 393190792Sgshapiro _res.retry = retry; 393290792Sgshapiro#endif /* NAMED_BIND */ 393338032Speter 393464562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 393538032Speter 393664562Sgshapiro /* Found an answer */ 393764562Sgshapiro if (ans != NULL) 393864562Sgshapiro { 393964562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 394090792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 394190792Sgshapiro sm_free(s->s_namecanon.nc_cname); 394290792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 394364562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 394464562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 394564562Sgshapiro else 394664562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 394771345Sgshapiro if (tTd(9, 1)) 394890792Sgshapiro sm_dprintf("FOUND %s\n", ans); 394964562Sgshapiro return cp; 395038032Speter } 395138032Speter 395264562Sgshapiro 395364562Sgshapiro /* No match found */ 395438032Speter s->s_namecanon.nc_errno = errno; 395590792Sgshapiro#if NAMED_BIND 395638032Speter s->s_namecanon.nc_herrno = h_errno; 395764562Sgshapiro if (tTd(9, 1)) 395890792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 395964562Sgshapiro switch (h_errno) 396038032Speter { 396164562Sgshapiro case TRY_AGAIN: 396264562Sgshapiro if (UseNameServer) 396364562Sgshapiro { 396464562Sgshapiro CurEnv->e_status = "4.4.3"; 396564562Sgshapiro message("851 %s: Name server timeout", 396664562Sgshapiro shortenstring(name, 33)); 396764562Sgshapiro } 396864562Sgshapiro *statp = EX_TEMPFAIL; 396964562Sgshapiro break; 397064562Sgshapiro 397164562Sgshapiro case HOST_NOT_FOUND: 397264562Sgshapiro case NO_DATA: 397364562Sgshapiro *statp = EX_NOHOST; 397464562Sgshapiro break; 397564562Sgshapiro 397664562Sgshapiro case NO_RECOVERY: 397764562Sgshapiro *statp = EX_SOFTWARE; 397864562Sgshapiro break; 397964562Sgshapiro 398064562Sgshapiro default: 398164562Sgshapiro *statp = EX_UNAVAILABLE; 398264562Sgshapiro break; 398338032Speter } 398490792Sgshapiro#else /* NAMED_BIND */ 398564562Sgshapiro if (tTd(9, 1)) 398690792Sgshapiro sm_dprintf("FAIL\n"); 398764562Sgshapiro *statp = EX_NOHOST; 398890792Sgshapiro#endif /* NAMED_BIND */ 398964562Sgshapiro s->s_namecanon.nc_stat = *statp; 399064562Sgshapiro return NULL; 399138032Speter} 399238032Speter/* 399390792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 399438032Speter** 399538032Speter** Parameters: 399690792Sgshapiro** map -- a pointer to this map. 399790792Sgshapiro** args -- argument string. 399838032Speter** 399938032Speter** Returns: 400090792Sgshapiro** true. 400138032Speter*/ 400238032Speter 400338032Speterbool 400438032Speterhost_map_init(map, args) 400538032Speter MAP *map; 400638032Speter char *args; 400738032Speter{ 400838032Speter register char *p = args; 400938032Speter 401038032Speter for (;;) 401138032Speter { 401238032Speter while (isascii(*p) && isspace(*p)) 401338032Speter p++; 401438032Speter if (*p != '-') 401538032Speter break; 401638032Speter switch (*++p) 401738032Speter { 401838032Speter case 'a': 401938032Speter map->map_app = ++p; 402038032Speter break; 402138032Speter 402238032Speter case 'T': 402338032Speter map->map_tapp = ++p; 402438032Speter break; 402538032Speter 402638032Speter case 'm': 402738032Speter map->map_mflags |= MF_MATCHONLY; 402838032Speter break; 402938032Speter 403038032Speter case 't': 403138032Speter map->map_mflags |= MF_NODEFER; 403238032Speter break; 403364562Sgshapiro 403464562Sgshapiro case 'S': /* only for consistency */ 403564562Sgshapiro map->map_spacesub = *++p; 403664562Sgshapiro break; 403764562Sgshapiro 403864562Sgshapiro case 'D': 403964562Sgshapiro map->map_mflags |= MF_DEFER; 404064562Sgshapiro break; 404190792Sgshapiro 404290792Sgshapiro case 'd': 404390792Sgshapiro { 404490792Sgshapiro char *h; 404590792Sgshapiro 404690792Sgshapiro while (isascii(*++p) && isspace(*p)) 404790792Sgshapiro continue; 404890792Sgshapiro h = strchr(p, ' '); 404990792Sgshapiro if (h != NULL) 405090792Sgshapiro *h = '\0'; 405190792Sgshapiro map->map_timeout = convtime(p, 's'); 405290792Sgshapiro if (h != NULL) 405390792Sgshapiro *h = ' '; 405490792Sgshapiro } 405590792Sgshapiro break; 405690792Sgshapiro 405790792Sgshapiro case 'r': 405890792Sgshapiro while (isascii(*++p) && isspace(*p)) 405990792Sgshapiro continue; 406090792Sgshapiro map->map_retry = atoi(p); 406190792Sgshapiro break; 406238032Speter } 406338032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 406438032Speter p++; 406538032Speter if (*p != '\0') 406638032Speter *p++ = '\0'; 406738032Speter } 406838032Speter if (map->map_app != NULL) 406938032Speter map->map_app = newstr(map->map_app); 407038032Speter if (map->map_tapp != NULL) 407138032Speter map->map_tapp = newstr(map->map_tapp); 407290792Sgshapiro return true; 407338032Speter} 407490792Sgshapiro 407564562Sgshapiro#if NETINET6 407664562Sgshapiro/* 407764562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 407864562Sgshapiro** 407964562Sgshapiro** Parameters: 408064562Sgshapiro** s6a -- a pointer to an in6_addr structure. 408164562Sgshapiro** dst -- buffer to store result in 408264562Sgshapiro** dst_len -- size of dst buffer 408364562Sgshapiro** 408464562Sgshapiro** Returns: 408564562Sgshapiro** A printable version of that structure. 408664562Sgshapiro*/ 408790792Sgshapiro 408864562Sgshapirochar * 408964562Sgshapiroanynet_ntop(s6a, dst, dst_len) 409064562Sgshapiro struct in6_addr *s6a; 409164562Sgshapiro char *dst; 409264562Sgshapiro size_t dst_len; 409364562Sgshapiro{ 409464562Sgshapiro register char *ap; 409564562Sgshapiro 409664562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 409764562Sgshapiro ap = (char *) inet_ntop(AF_INET, 409864562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 409964562Sgshapiro dst, dst_len); 410064562Sgshapiro else 410190792Sgshapiro { 410290792Sgshapiro char *d; 410390792Sgshapiro size_t sz; 410490792Sgshapiro 410590792Sgshapiro /* Save pointer to beginning of string */ 410690792Sgshapiro d = dst; 410790792Sgshapiro 410890792Sgshapiro /* Add IPv6: protocol tag */ 410990792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 411090792Sgshapiro if (sz >= dst_len) 411190792Sgshapiro return NULL; 411290792Sgshapiro dst += sz; 411390792Sgshapiro dst_len -= sz; 411464562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 411590792Sgshapiro 411690792Sgshapiro /* Restore pointer to beginning of string */ 411790792Sgshapiro if (ap != NULL) 411890792Sgshapiro ap = d; 411990792Sgshapiro } 412064562Sgshapiro return ap; 412164562Sgshapiro} 412290792Sgshapiro 412390792Sgshapiro/* 412490792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 412590792Sgshapiro** 412690792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 412790792Sgshapiro** 412890792Sgshapiro** Parameters: 412990792Sgshapiro** family -- address family 413090792Sgshapiro** src -- string 413190792Sgshapiro** dst -- destination address structure 413290792Sgshapiro** 413390792Sgshapiro** Returns: 413490792Sgshapiro** 1 if the address was valid 413590792Sgshapiro** 0 if the address wasn't parseable 413690792Sgshapiro** -1 if error 413790792Sgshapiro*/ 413890792Sgshapiro 413990792Sgshapiroint 414090792Sgshapiroanynet_pton(family, src, dst) 414190792Sgshapiro int family; 414290792Sgshapiro const char *src; 414390792Sgshapiro void *dst; 414490792Sgshapiro{ 414590792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 414690792Sgshapiro src += 5; 414790792Sgshapiro return inet_pton(family, src, dst); 414890792Sgshapiro} 414964562Sgshapiro#endif /* NETINET6 */ 415090792Sgshapiro/* 415138032Speter** ANYNET_NTOA -- convert a network address to printable form. 415238032Speter** 415338032Speter** Parameters: 415438032Speter** sap -- a pointer to a sockaddr structure. 415538032Speter** 415638032Speter** Returns: 415738032Speter** A printable version of that sockaddr. 415838032Speter*/ 415938032Speter 416038032Speter#ifdef USE_SOCK_STREAM 416138032Speter 416264562Sgshapiro# if NETLINK 416364562Sgshapiro# include <net/if_dl.h> 416464562Sgshapiro# endif /* NETLINK */ 416538032Speter 416638032Speterchar * 416738032Speteranynet_ntoa(sap) 416838032Speter register SOCKADDR *sap; 416938032Speter{ 417038032Speter register char *bp; 417138032Speter register char *ap; 417238032Speter int l; 417338032Speter static char buf[100]; 417438032Speter 417538032Speter /* check for null/zero family */ 417638032Speter if (sap == NULL) 417738032Speter return "NULLADDR"; 417838032Speter if (sap->sa.sa_family == 0) 417938032Speter return "0"; 418038032Speter 418138032Speter switch (sap->sa.sa_family) 418238032Speter { 418364562Sgshapiro# if NETUNIX 418438032Speter case AF_UNIX: 418564562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 418690792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]", 418790792Sgshapiro sap->sunix.sun_path); 418864562Sgshapiro else 418990792Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf); 419038032Speter return buf; 419164562Sgshapiro# endif /* NETUNIX */ 419238032Speter 419364562Sgshapiro# if NETINET 419438032Speter case AF_INET: 419564562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 419664562Sgshapiro# endif /* NETINET */ 419738032Speter 419864562Sgshapiro# if NETINET6 419964562Sgshapiro case AF_INET6: 420064562Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf); 420164562Sgshapiro if (ap != NULL) 420264562Sgshapiro return ap; 420364562Sgshapiro break; 420464562Sgshapiro# endif /* NETINET6 */ 420564562Sgshapiro 420664562Sgshapiro# if NETLINK 420738032Speter case AF_LINK: 420890792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[LINK: %s]", 420990792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 421038032Speter return buf; 421164562Sgshapiro# endif /* NETLINK */ 421238032Speter default: 421338032Speter /* this case is needed when nothing is #defined */ 421438032Speter /* in order to keep the switch syntactically correct */ 421538032Speter break; 421638032Speter } 421738032Speter 421838032Speter /* unknown family -- just dump bytes */ 421990792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 422038032Speter bp = &buf[strlen(buf)]; 422138032Speter ap = sap->sa.sa_data; 422238032Speter for (l = sizeof sap->sa.sa_data; --l >= 0; ) 422338032Speter { 422490792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 422590792Sgshapiro *ap++ & 0377); 422638032Speter bp += 3; 422738032Speter } 422838032Speter *--bp = '\0'; 422938032Speter return buf; 423038032Speter} 423190792Sgshapiro/* 423238032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 423338032Speter** 423438032Speter** Parameters: 423538032Speter** sap -- SOCKADDR pointer 423638032Speter** 423738032Speter** Returns: 423838032Speter** text representation of host name. 423938032Speter** 424038032Speter** Side Effects: 424138032Speter** none. 424238032Speter*/ 424338032Speter 424438032Speterchar * 424538032Speterhostnamebyanyaddr(sap) 424638032Speter register SOCKADDR *sap; 424738032Speter{ 424838032Speter register struct hostent *hp; 424964562Sgshapiro# if NAMED_BIND 425038032Speter int saveretry; 425164562Sgshapiro# endif /* NAMED_BIND */ 425264562Sgshapiro# if NETINET6 425364562Sgshapiro struct in6_addr in6_addr; 425464562Sgshapiro# endif /* NETINET6 */ 425538032Speter 425664562Sgshapiro# if NAMED_BIND 425738032Speter /* shorten name server timeout to avoid higher level timeouts */ 425838032Speter saveretry = _res.retry; 425964562Sgshapiro if (_res.retry * _res.retrans > 20) 426064562Sgshapiro _res.retry = 20 / _res.retrans; 426164562Sgshapiro# endif /* NAMED_BIND */ 426238032Speter 426338032Speter switch (sap->sa.sa_family) 426438032Speter { 426564562Sgshapiro# if NETINET 426638032Speter case AF_INET: 426738032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 426890792Sgshapiro INADDRSZ, AF_INET); 426938032Speter break; 427064562Sgshapiro# endif /* NETINET */ 427138032Speter 427264562Sgshapiro# if NETINET6 427364562Sgshapiro case AF_INET6: 427464562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 427590792Sgshapiro IN6ADDRSZ, AF_INET6); 427664562Sgshapiro break; 427764562Sgshapiro# endif /* NETINET6 */ 427864562Sgshapiro 427964562Sgshapiro# if NETISO 428038032Speter case AF_ISO: 428138032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 428290792Sgshapiro sizeof sap->siso.siso_addr, AF_ISO); 428338032Speter break; 428464562Sgshapiro# endif /* NETISO */ 428538032Speter 428664562Sgshapiro# if NETUNIX 428738032Speter case AF_UNIX: 428838032Speter hp = NULL; 428938032Speter break; 429064562Sgshapiro# endif /* NETUNIX */ 429138032Speter 429238032Speter default: 429390792Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data, 429490792Sgshapiro sap->sa.sa_family); 429538032Speter break; 429638032Speter } 429738032Speter 429864562Sgshapiro# if NAMED_BIND 429938032Speter _res.retry = saveretry; 430064562Sgshapiro# endif /* NAMED_BIND */ 430138032Speter 430264562Sgshapiro# if NETINET || NETINET6 430364562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 430464562Sgshapiro# if NETINET6 430564562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 430664562Sgshapiro# endif /* NETINET6 */ 430764562Sgshapiro# if NETINET 430864562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 430964562Sgshapiro# endif /* NETINET */ 431064562Sgshapiro ) 431171345Sgshapiro { 431271345Sgshapiro char *name; 431371345Sgshapiro 431490792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 431590792Sgshapiro# if NETINET6 431671345Sgshapiro if (name == hp->h_name) 431771345Sgshapiro { 431871345Sgshapiro static char n[MAXNAME + 1]; 431971345Sgshapiro 432071345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 432190792Sgshapiro (void) sm_strlcpy(n, name, sizeof n); 432271345Sgshapiro name = n; 432371345Sgshapiro } 432471345Sgshapiro freehostent(hp); 432590792Sgshapiro# endif /* NETINET6 */ 432671345Sgshapiro return name; 432771345Sgshapiro } 432864562Sgshapiro# endif /* NETINET || NETINET6 */ 432971345Sgshapiro 433090792Sgshapiro# if NETINET6 433171345Sgshapiro if (hp != NULL) 433271345Sgshapiro { 433371345Sgshapiro freehostent(hp); 433471345Sgshapiro hp = NULL; 433571345Sgshapiro } 433690792Sgshapiro# endif /* NETINET6 */ 433771345Sgshapiro 433864562Sgshapiro# if NETUNIX 433964562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 434038032Speter return "localhost"; 434164562Sgshapiro# endif /* NETUNIX */ 434238032Speter { 434338032Speter static char buf[203]; 434438032Speter 434590792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[%.200s]", 434690792Sgshapiro anynet_ntoa(sap)); 434738032Speter return buf; 434838032Speter } 434938032Speter} 435064562Sgshapiro#endif /* USE_SOCK_STREAM */ 4351