daemon.c revision 90792
138032Speter/* 273188Sgshapiro * Copyright (c) 1998-2001 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 1690792SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.603 2001/12/31 19:46:38 gshapiro 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; 15764562Sgshapiro# if NETUNIX 15842575Speter extern int ControlSocket; 15964562Sgshapiro# endif /* NETUNIX */ 16064562Sgshapiro extern ENVELOPE BlankEnvelope; 16190792Sgshapiro extern bool refuseconnections __P((char *, ENVELOPE *, int, bool)); 16238032Speter 16338032Speter 16490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 16538032Speter { 16664562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 16790792Sgshapiro Daemons[idx].d_firsttime = true; 16864562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 16938032Speter } 17071345Sgshapiro 17138032Speter /* 17238032Speter ** Try to actually open the connection. 17338032Speter */ 17438032Speter 17538032Speter if (tTd(15, 1)) 17664562Sgshapiro { 17790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 17871345Sgshapiro { 17990792Sgshapiro sm_dprintf("getrequests: daemon %s: port %d\n", 18090792Sgshapiro Daemons[idx].d_name, 18190792Sgshapiro ntohs(Daemons[idx].d_port)); 18271345Sgshapiro } 18364562Sgshapiro } 18438032Speter 18538032Speter /* get a socket for the SMTP connection */ 18690792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 18790792Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true); 18838032Speter 18942575Speter if (opencontrolsocket() < 0) 19042575Speter sm_syslog(LOG_WARNING, NOQID, 19143730Speter "daemon could not open control socket %s: %s", 19290792Sgshapiro ControlSocketName, sm_errstring(errno)); 19342575Speter 19490792Sgshapiro /* If there are any queue runners released reapchild() co-ord's */ 19590792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 19638032Speter 19790792Sgshapiro /* write the pid to file, command line args to syslog */ 19864562Sgshapiro log_sendmail_pid(e); 19938032Speter 20090792Sgshapiro#if XDEBUG 20138032Speter { 20238032Speter char jbuf[MAXHOSTNAMELEN]; 20338032Speter 20438032Speter expand("\201j", jbuf, sizeof jbuf, e); 20538032Speter j_has_dot = strchr(jbuf, '.') != NULL; 20638032Speter } 20790792Sgshapiro#endif /* XDEBUG */ 20838032Speter 20942575Speter /* Add parent process as first item */ 21090792Sgshapiro proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1); 21142575Speter 21238032Speter if (tTd(15, 1)) 21364562Sgshapiro { 21490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 21590792Sgshapiro sm_dprintf("getrequests: daemon %s: %d\n", 21664562Sgshapiro Daemons[idx].d_name, 21764562Sgshapiro Daemons[idx].d_socket); 21864562Sgshapiro } 21938032Speter 22038032Speter for (;;) 22138032Speter { 22238032Speter register pid_t pid; 22338032Speter auto SOCKADDR_LEN_T lotherend; 22490792Sgshapiro bool timedout = false; 22590792Sgshapiro bool control = false; 22664562Sgshapiro int save_errno; 22738032Speter int pipefd[2]; 22890792Sgshapiro time_t now; 22990792Sgshapiro#if STARTTLS 23066494Sgshapiro long seed; 23190792Sgshapiro#endif /* STARTTLS */ 23238032Speter 23338032Speter /* see if we are rejecting connections */ 23490792Sgshapiro (void) sm_blocksignal(SIGALRM); 23564562Sgshapiro 23677349Sgshapiro if (ShutdownRequest != NULL) 23777349Sgshapiro shutdown_daemon(); 23877349Sgshapiro else if (RestartRequest != NULL) 23977349Sgshapiro restart_daemon(); 24090792Sgshapiro else if (RestartWorkGroup) 24190792Sgshapiro restart_marked_work_groups(); 24277349Sgshapiro 24390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 24471345Sgshapiro { 24590792Sgshapiro /* 24690792Sgshapiro ** XXX do this call outside the loop? 24790792Sgshapiro ** no: refuse_connections may sleep(). 24890792Sgshapiro */ 24971345Sgshapiro 25090792Sgshapiro now = curtime(); 25190792Sgshapiro if (now < Daemons[idx].d_refuse_connections_until) 25264562Sgshapiro continue; 25390792Sgshapiro if (bitnset(D_DISABLE, Daemons[idx].d_flags)) 25490792Sgshapiro continue; 25590792Sgshapiro if (refuseconnections(Daemons[idx].d_name, e, idx, 25690792Sgshapiro curdaemon == idx)) 25738032Speter { 25864562Sgshapiro if (Daemons[idx].d_socket >= 0) 25942575Speter { 26071345Sgshapiro /* close socket so peer fails quickly */ 26171345Sgshapiro (void) close(Daemons[idx].d_socket); 26271345Sgshapiro Daemons[idx].d_socket = -1; 26342575Speter } 26442575Speter 26542575Speter /* refuse connections for next 15 seconds */ 26690792Sgshapiro Daemons[idx].d_refuse_connections_until = now + 15; 26738032Speter } 26864562Sgshapiro else if (Daemons[idx].d_socket < 0 || 26964562Sgshapiro Daemons[idx].d_firsttime) 27042575Speter { 27190792Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel > 8) 27271345Sgshapiro sm_syslog(LOG_INFO, NOQID, 27371345Sgshapiro "accepting connections again for daemon %s", 27471345Sgshapiro Daemons[idx].d_name); 27564562Sgshapiro 27671345Sgshapiro /* arrange to (re)open the socket if needed */ 27790792Sgshapiro (void) opendaemonsocket(&Daemons[idx], false); 27890792Sgshapiro Daemons[idx].d_firsttime = false; 27942575Speter } 28038032Speter } 28138032Speter 28277349Sgshapiro /* May have been sleeping above, check again */ 28377349Sgshapiro if (ShutdownRequest != NULL) 28477349Sgshapiro shutdown_daemon(); 28577349Sgshapiro else if (RestartRequest != NULL) 28677349Sgshapiro restart_daemon(); 28790792Sgshapiro else if (RestartWorkGroup) 28890792Sgshapiro restart_marked_work_groups(); 28977349Sgshapiro 29090792Sgshapiro getrequests_checkdiskspace(e); 29171345Sgshapiro 29290792Sgshapiro#if XDEBUG 29338032Speter /* check for disaster */ 29438032Speter { 29538032Speter char jbuf[MAXHOSTNAMELEN]; 29638032Speter 29738032Speter expand("\201j", jbuf, sizeof jbuf, e); 29838032Speter if (!wordinclass(jbuf, 'w')) 29938032Speter { 30038032Speter dumpstate("daemon lost $j"); 30138032Speter sm_syslog(LOG_ALERT, NOQID, 30264562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 30338032Speter abort(); 30438032Speter } 30538032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 30638032Speter { 30738032Speter dumpstate("daemon $j lost dot"); 30838032Speter sm_syslog(LOG_ALERT, NOQID, 30964562Sgshapiro "daemon process $j lost dot; see syslog"); 31038032Speter abort(); 31138032Speter } 31238032Speter } 31390792Sgshapiro#endif /* XDEBUG */ 31438032Speter 31590792Sgshapiro#if 0 31638032Speter /* 31738032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 31838032Speter ** fix the SVr4 problem. But it seems to have gone away, 31938032Speter ** so is it worth doing this? 32038032Speter */ 32138032Speter 32242575Speter if (DaemonSocket >= 0 && 32390792Sgshapiro SetNonBlocking(DaemonSocket, false) < 0) 32438032Speter log an error here; 32590792Sgshapiro#endif /* 0 */ 32690792Sgshapiro (void) sm_releasesignal(SIGALRM); 32764562Sgshapiro 32838032Speter for (;;) 32938032Speter { 33090792Sgshapiro bool setproc = false; 33142575Speter int highest = -1; 33238032Speter fd_set readfds; 33338032Speter struct timeval timeout; 33438032Speter 33577349Sgshapiro if (ShutdownRequest != NULL) 33677349Sgshapiro shutdown_daemon(); 33777349Sgshapiro else if (RestartRequest != NULL) 33877349Sgshapiro restart_daemon(); 33990792Sgshapiro else if (RestartWorkGroup) 34090792Sgshapiro restart_marked_work_groups(); 34177349Sgshapiro 34238032Speter FD_ZERO(&readfds); 34342575Speter 34490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 34542575Speter { 34664562Sgshapiro /* wait for a connection */ 34764562Sgshapiro if (Daemons[idx].d_socket >= 0) 34864562Sgshapiro { 34971345Sgshapiro if (!setproc && 35071345Sgshapiro !bitnset(D_ETRNONLY, 35171345Sgshapiro Daemons[idx].d_flags)) 35264562Sgshapiro { 35390792Sgshapiro sm_setproctitle(true, e, 35464562Sgshapiro "accepting connections"); 35590792Sgshapiro setproc = true; 35664562Sgshapiro } 35764562Sgshapiro if (Daemons[idx].d_socket > highest) 35864562Sgshapiro highest = Daemons[idx].d_socket; 35990792Sgshapiro SM_FD_SET(Daemons[idx].d_socket, 36090792Sgshapiro &readfds); 36164562Sgshapiro } 36242575Speter } 36364562Sgshapiro 36490792Sgshapiro#if NETUNIX 36542575Speter if (ControlSocket >= 0) 36642575Speter { 36742575Speter if (ControlSocket > highest) 36842575Speter highest = ControlSocket; 36990792Sgshapiro SM_FD_SET(ControlSocket, &readfds); 37042575Speter } 37190792Sgshapiro#endif /* NETUNIX */ 37264562Sgshapiro 37377349Sgshapiro timeout.tv_sec = 5; 37438032Speter timeout.tv_usec = 0; 37538032Speter 37642575Speter t = select(highest + 1, FDSET_CAST &readfds, 37764562Sgshapiro NULL, NULL, &timeout); 37842575Speter 37977349Sgshapiro /* Did someone signal while waiting? */ 38077349Sgshapiro if (ShutdownRequest != NULL) 38177349Sgshapiro shutdown_daemon(); 38277349Sgshapiro else if (RestartRequest != NULL) 38377349Sgshapiro restart_daemon(); 38490792Sgshapiro else if (RestartWorkGroup) 38590792Sgshapiro restart_marked_work_groups(); 38671345Sgshapiro 38771345Sgshapiro 38877349Sgshapiro 38990792Sgshapiro curdaemon = -1; 39090792Sgshapiro if (doqueuerun()) 39190792Sgshapiro (void) runqueue(true, false, false, false); 39271345Sgshapiro 39342575Speter if (t <= 0) 39442575Speter { 39590792Sgshapiro timedout = true; 39642575Speter break; 39742575Speter } 39838032Speter 39990792Sgshapiro control = false; 40038032Speter errno = 0; 40164562Sgshapiro 40264562Sgshapiro /* look "round-robin" for an active socket */ 40390792Sgshapiro if ((idx = olddaemon + 1) >= NDaemons) 40464562Sgshapiro idx = 0; 40590792Sgshapiro for (i = 0; i < NDaemons; i++) 40642575Speter { 40764562Sgshapiro if (Daemons[idx].d_socket >= 0 && 40890792Sgshapiro SM_FD_ISSET(Daemons[idx].d_socket, 40990792Sgshapiro &readfds)) 41064562Sgshapiro { 41164562Sgshapiro lotherend = Daemons[idx].d_socksize; 41273188Sgshapiro memset(&RealHostAddr, '\0', 41373188Sgshapiro sizeof RealHostAddr); 41464562Sgshapiro t = accept(Daemons[idx].d_socket, 41564562Sgshapiro (struct sockaddr *)&RealHostAddr, 41664562Sgshapiro &lotherend); 41773188Sgshapiro 41873188Sgshapiro /* 41973188Sgshapiro ** If remote side closes before 42073188Sgshapiro ** accept() finishes, sockaddr 42173188Sgshapiro ** might not be fully filled in. 42273188Sgshapiro */ 42373188Sgshapiro 42473188Sgshapiro if (t >= 0 && 42573188Sgshapiro (lotherend == 0 || 42673188Sgshapiro# ifdef BSD4_4_SOCKADDR 42773188Sgshapiro RealHostAddr.sa.sa_len == 0 || 42873188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 42973188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 43073188Sgshapiro { 43173188Sgshapiro (void) close(t); 43273188Sgshapiro t = -1; 43373188Sgshapiro errno = EINVAL; 43473188Sgshapiro } 43564562Sgshapiro olddaemon = curdaemon = idx; 43664562Sgshapiro break; 43764562Sgshapiro } 43890792Sgshapiro if (++idx >= NDaemons) 43964562Sgshapiro idx = 0; 44042575Speter } 44190792Sgshapiro#if NETUNIX 44264562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 44390792Sgshapiro SM_FD_ISSET(ControlSocket, &readfds)) 44442575Speter { 44542575Speter struct sockaddr_un sa_un; 44642575Speter 44742575Speter lotherend = sizeof sa_un; 44873188Sgshapiro memset(&sa_un, '\0', sizeof sa_un); 44942575Speter t = accept(ControlSocket, 45042575Speter (struct sockaddr *)&sa_un, 45142575Speter &lotherend); 45273188Sgshapiro 45373188Sgshapiro /* 45473188Sgshapiro ** If remote side closes before 45573188Sgshapiro ** accept() finishes, sockaddr 45673188Sgshapiro ** might not be fully filled in. 45773188Sgshapiro */ 45873188Sgshapiro 45973188Sgshapiro if (t >= 0 && 46073188Sgshapiro (lotherend == 0 || 46173188Sgshapiro# ifdef BSD4_4_SOCKADDR 46273188Sgshapiro sa_un.sun_len == 0 || 46373188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 46473188Sgshapiro sa_un.sun_family != AF_UNIX)) 46573188Sgshapiro { 46673188Sgshapiro (void) close(t); 46773188Sgshapiro t = -1; 46873188Sgshapiro errno = EINVAL; 46973188Sgshapiro } 47073188Sgshapiro if (t >= 0) 47190792Sgshapiro control = true; 47242575Speter } 47390792Sgshapiro#else /* NETUNIX */ 47471345Sgshapiro if (curdaemon == -1) 47571345Sgshapiro { 47671345Sgshapiro /* No daemon to service */ 47771345Sgshapiro continue; 47871345Sgshapiro } 47990792Sgshapiro#endif /* NETUNIX */ 48038032Speter if (t >= 0 || errno != EINTR) 48138032Speter break; 48238032Speter } 48342575Speter if (timedout) 48442575Speter { 48590792Sgshapiro timedout = false; 48642575Speter continue; 48742575Speter } 48864562Sgshapiro save_errno = errno; 48990792Sgshapiro (void) sm_blocksignal(SIGALRM); 49038032Speter if (t < 0) 49138032Speter { 49264562Sgshapiro errno = save_errno; 49338032Speter syserr("getrequests: accept"); 49438032Speter 49538032Speter /* arrange to re-open the socket next time around */ 49664562Sgshapiro (void) close(Daemons[curdaemon].d_socket); 49764562Sgshapiro Daemons[curdaemon].d_socket = -1; 49890792Sgshapiro#if SO_REUSEADDR_IS_BROKEN 49964562Sgshapiro /* 50064562Sgshapiro ** Give time for bound socket to be released. 50164562Sgshapiro ** This creates a denial-of-service if you can 50264562Sgshapiro ** force accept() to fail on affected systems. 50364562Sgshapiro */ 50464562Sgshapiro 50590792Sgshapiro Daemons[curdaemon].d_refuse_connections_until = curtime() + 15; 50690792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */ 50738032Speter continue; 50838032Speter } 50938032Speter 51064562Sgshapiro if (!control) 51164562Sgshapiro { 51264562Sgshapiro /* set some daemon related macros */ 51364562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 51464562Sgshapiro { 51564562Sgshapiro case AF_UNSPEC: 51690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 51790792Sgshapiro macid("{daemon_family}"), "unspec"); 51864562Sgshapiro break; 51990792Sgshapiro#if _FFR_DAEMON_NETUNIX 52090792Sgshapiro# if NETUNIX 52190792Sgshapiro case AF_UNIX: 52290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 52390792Sgshapiro macid("{daemon_family}"), "local"); 52490792Sgshapiro break; 52590792Sgshapiro# endif /* NETUNIX */ 52690792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 52790792Sgshapiro#if NETINET 52864562Sgshapiro case AF_INET: 52990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53090792Sgshapiro macid("{daemon_family}"), "inet"); 53164562Sgshapiro break; 53290792Sgshapiro#endif /* NETINET */ 53390792Sgshapiro#if NETINET6 53464562Sgshapiro case AF_INET6: 53590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53690792Sgshapiro macid("{daemon_family}"), "inet6"); 53764562Sgshapiro break; 53890792Sgshapiro#endif /* NETINET6 */ 53990792Sgshapiro#if NETISO 54064562Sgshapiro case AF_ISO: 54190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54290792Sgshapiro macid("{daemon_family}"), "iso"); 54364562Sgshapiro break; 54490792Sgshapiro#endif /* NETISO */ 54590792Sgshapiro#if NETNS 54664562Sgshapiro case AF_NS: 54790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54890792Sgshapiro macid("{daemon_family}"), "ns"); 54964562Sgshapiro break; 55090792Sgshapiro#endif /* NETNS */ 55190792Sgshapiro#if NETX25 55264562Sgshapiro case AF_CCITT: 55390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55490792Sgshapiro macid("{daemon_family}"), "x.25"); 55564562Sgshapiro break; 55690792Sgshapiro#endif /* NETX25 */ 55764562Sgshapiro } 55890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55990792Sgshapiro macid("{daemon_name}"), 56090792Sgshapiro Daemons[curdaemon].d_name); 56164562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 56290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56390792Sgshapiro macid("{daemon_flags}"), 56490792Sgshapiro Daemons[curdaemon].d_mflags); 56564562Sgshapiro else 56690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56790792Sgshapiro macid("{daemon_flags}"), ""); 56864562Sgshapiro } 56964562Sgshapiro 57038032Speter /* 57138032Speter ** Create a subprocess to process the mail. 57238032Speter */ 57338032Speter 57438032Speter if (tTd(15, 2)) 57590792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 57638032Speter 57738032Speter /* 57890792Sgshapiro ** Advance state of PRNG. 57990792Sgshapiro ** This is necessary because otherwise all child processes 58064562Sgshapiro ** will produce the same PRN sequence and hence the selection 58164562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 58264562Sgshapiro ** are not "really" random. 58364562Sgshapiro */ 58490792Sgshapiro#if STARTTLS 58590792Sgshapiro /* XXX get some better "random" data? */ 58666494Sgshapiro seed = get_random(); 58790792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 58890792Sgshapiro sizeof NextDiskSpaceCheck); 58990792Sgshapiro RAND_seed((void *) &now, sizeof now); 59066494Sgshapiro RAND_seed((void *) &seed, sizeof seed); 59190792Sgshapiro#else /* STARTTLS */ 59264562Sgshapiro (void) get_random(); 59390792Sgshapiro#endif /* STARTTLS */ 59464562Sgshapiro 59590792Sgshapiro#if NAMED_BIND 59664562Sgshapiro /* 59790792Sgshapiro ** Update MX records for FallBackMX. 59890792Sgshapiro ** Let's hope this is fast otherwise we screw up the 59990792Sgshapiro ** response time. 60090792Sgshapiro */ 60190792Sgshapiro 60290792Sgshapiro if (FallBackMX != NULL) 60390792Sgshapiro (void) getfallbackmxrr(FallBackMX); 60490792Sgshapiro#endif /* NAMED_BIND */ 60590792Sgshapiro 60690792Sgshapiro#if !PROFILING 60790792Sgshapiro /* 60838032Speter ** Create a pipe to keep the child from writing to the 60938032Speter ** socket until after the parent has closed it. Otherwise 61038032Speter ** the parent may hang if the child has closed it first. 61138032Speter */ 61238032Speter 61338032Speter if (pipe(pipefd) < 0) 61438032Speter pipefd[0] = pipefd[1] = -1; 61538032Speter 61690792Sgshapiro (void) sm_blocksignal(SIGCHLD); 61738032Speter pid = fork(); 61838032Speter if (pid < 0) 61938032Speter { 62038032Speter syserr("daemon: cannot fork"); 62138032Speter if (pipefd[0] != -1) 62238032Speter { 62338032Speter (void) close(pipefd[0]); 62438032Speter (void) close(pipefd[1]); 62538032Speter } 62690792Sgshapiro (void) sm_releasesignal(SIGCHLD); 62764562Sgshapiro (void) sleep(10); 62838032Speter (void) close(t); 62938032Speter continue; 63038032Speter } 63190792Sgshapiro 63290792Sgshapiro#else /* !PROFILING */ 63371345Sgshapiro pid = 0; 63490792Sgshapiro#endif /* !PROFILING */ 63538032Speter 63638032Speter if (pid == 0) 63738032Speter { 63838032Speter char *p; 63990792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 64038032Speter 64138032Speter /* 64238032Speter ** CHILD -- return to caller. 64338032Speter ** Collect verified idea of sending host. 64438032Speter ** Verify calling user id if possible here. 64538032Speter */ 64638032Speter 64777349Sgshapiro /* Reset global flags */ 64877349Sgshapiro RestartRequest = NULL; 64990792Sgshapiro RestartWorkGroup = false; 65077349Sgshapiro ShutdownRequest = NULL; 65177349Sgshapiro PendingSignal = 0; 65290792Sgshapiro CurrentPid = getpid(); 65377349Sgshapiro 65490792Sgshapiro (void) sm_releasesignal(SIGALRM); 65590792Sgshapiro (void) sm_releasesignal(SIGCHLD); 65690792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 65790792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 65890792Sgshapiro (void) sm_signal(SIGTERM, intsig); 65977349Sgshapiro 66090792Sgshapiro /* turn on profiling */ 66190792Sgshapiro /* SM_PROF(0); */ 66290792Sgshapiro 66390792Sgshapiro /* 66490792Sgshapiro ** Initialize exception stack and default exception 66590792Sgshapiro ** handler for child process. 66690792Sgshapiro */ 66790792Sgshapiro 66890792Sgshapiro sm_exc_newthread(fatal_error); 66990792Sgshapiro 67064562Sgshapiro if (!control) 67164562Sgshapiro { 67290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 67390792Sgshapiro macid("{daemon_addr}"), 67490792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 67590792Sgshapiro (void) sm_snprintf(status, sizeof status, "%d", 67664562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 67790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 67890792Sgshapiro macid("{daemon_port}"), status); 67964562Sgshapiro } 68064562Sgshapiro 68190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 68264562Sgshapiro { 68364562Sgshapiro if (Daemons[idx].d_socket >= 0) 68464562Sgshapiro (void) close(Daemons[idx].d_socket); 68580785Sgshapiro Daemons[idx].d_socket = -1; 68664562Sgshapiro } 68742575Speter clrcontrol(); 68838032Speter 68964562Sgshapiro /* Avoid SMTP daemon actions if control command */ 69064562Sgshapiro if (control) 69164562Sgshapiro { 69264562Sgshapiro /* Add control socket process */ 69390792Sgshapiro proc_list_add(CurrentPid, 69490792Sgshapiro "console socket child", 69590792Sgshapiro PROC_CONTROL_CHILD, 0, -1); 69664562Sgshapiro } 69764562Sgshapiro else 69864562Sgshapiro { 69964562Sgshapiro proc_list_clear(); 70042575Speter 70190792Sgshapiro /* clean up background delivery children */ 70290792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 70390792Sgshapiro 70464562Sgshapiro /* Add parent process as first child item */ 70590792Sgshapiro proc_list_add(CurrentPid, "daemon child", 70690792Sgshapiro PROC_DAEMON_CHILD, 0, -1); 70738032Speter 70864562Sgshapiro /* don't schedule queue runs if ETRN */ 70964562Sgshapiro QueueIntvl = 0; 71038032Speter 71190792Sgshapiro sm_setproctitle(true, e, "startup with %s", 71264562Sgshapiro anynet_ntoa(&RealHostAddr)); 71364562Sgshapiro } 71464562Sgshapiro 71590792Sgshapiro#if !PROFILING 71638032Speter if (pipefd[0] != -1) 71738032Speter { 71838032Speter auto char c; 71938032Speter 72038032Speter /* 72138032Speter ** Wait for the parent to close the write end 72238032Speter ** of the pipe, which we will see as an EOF. 72338032Speter ** This guarantees that we won't write to the 72438032Speter ** socket until after the parent has closed 72538032Speter ** the pipe. 72638032Speter */ 72738032Speter 72838032Speter /* close the write end of the pipe */ 72938032Speter (void) close(pipefd[1]); 73038032Speter 73138032Speter /* we shouldn't be interrupted, but ... */ 73238032Speter while (read(pipefd[0], &c, 1) < 0 && 73338032Speter errno == EINTR) 73438032Speter continue; 73538032Speter (void) close(pipefd[0]); 73638032Speter } 73790792Sgshapiro#endif /* !PROFILING */ 73838032Speter 73964562Sgshapiro /* control socket processing */ 74064562Sgshapiro if (control) 74164562Sgshapiro { 74264562Sgshapiro control_command(t, e); 74364562Sgshapiro /* NOTREACHED */ 74464562Sgshapiro exit(EX_SOFTWARE); 74564562Sgshapiro } 74664562Sgshapiro 74738032Speter /* determine host name */ 74838032Speter p = hostnamebyanyaddr(&RealHostAddr); 74990792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 75038032Speter p[MAXNAME] = '\0'; 75138032Speter RealHostName = newstr(p); 75264562Sgshapiro if (RealHostName[0] == '[') 75364562Sgshapiro { 75490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 75590792Sgshapiro macid("{client_resolve}"), 75690792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 75764562Sgshapiro } 75864562Sgshapiro else 75990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 76090792Sgshapiro macid("{client_resolve}"), "OK"); 76190792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 76238032Speter 76390792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 76490792Sgshapiro SM_TIME_DEFAULT, 76590792Sgshapiro (void *) &t, 76690792Sgshapiro SM_IO_RDONLY, 76790792Sgshapiro NULL)) == NULL || 76838032Speter (t = dup(t)) < 0 || 76990792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 77090792Sgshapiro SM_TIME_DEFAULT, 77190792Sgshapiro (void *) &t, 77290792Sgshapiro SM_IO_WRONLY, 77390792Sgshapiro NULL)) == NULL) 77438032Speter { 77590792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 77690792Sgshapiro t); 77790792Sgshapiro finis(false, true, EX_OK); 77838032Speter } 77990792Sgshapiro sm_io_automode(inchannel, outchannel); 78038032Speter 78138032Speter InChannel = inchannel; 78238032Speter OutChannel = outchannel; 78390792Sgshapiro DisConnected = false; 78438032Speter 78590792Sgshapiro#if XLA 78638032Speter if (!xla_host_ok(RealHostName)) 78738032Speter { 78864562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 78990792Sgshapiro finis(false, true, EX_OK); 79038032Speter } 79190792Sgshapiro#endif /* XLA */ 79264562Sgshapiro /* find out name for interface of connection */ 79390792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 79490792Sgshapiro NULL), &sa.sa, &len) == 0) 79564562Sgshapiro { 79664562Sgshapiro p = hostnamebyanyaddr(&sa); 79764562Sgshapiro if (tTd(15, 9)) 79890792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 79990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 80090792Sgshapiro macid("{if_name}"), p); 80164562Sgshapiro 80290792Sgshapiro /* 80390792Sgshapiro ** Do this only if it is not the loopback 80490792Sgshapiro ** interface. 80590792Sgshapiro */ 80690792Sgshapiro 80764562Sgshapiro if (!isloopback(sa)) 80864562Sgshapiro { 80990792Sgshapiro char *addr; 81090792Sgshapiro char family[5]; 81190792Sgshapiro 81290792Sgshapiro addr = anynet_ntoa(&sa); 81390792Sgshapiro (void) sm_snprintf(family, 81490792Sgshapiro sizeof(family), 81590792Sgshapiro "%d", sa.sa.sa_family); 81690792Sgshapiro macdefine(&BlankEnvelope.e_macro, 81790792Sgshapiro A_TEMP, 81890792Sgshapiro macid("{if_addr}"), addr); 81990792Sgshapiro macdefine(&BlankEnvelope.e_macro, 82090792Sgshapiro A_TEMP, 82190792Sgshapiro macid("{if_family}"), family); 82264562Sgshapiro if (tTd(15, 7)) 82390792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 82490792Sgshapiro addr, family); 82564562Sgshapiro } 82664562Sgshapiro else 82764562Sgshapiro { 82890792Sgshapiro macdefine(&BlankEnvelope.e_macro, 82990792Sgshapiro A_PERM, 83090792Sgshapiro macid("{if_addr}"), NULL); 83190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 83290792Sgshapiro A_PERM, 83390792Sgshapiro macid("{if_family}"), NULL); 83464562Sgshapiro } 83564562Sgshapiro } 83664562Sgshapiro else 83764562Sgshapiro { 83864562Sgshapiro if (tTd(15, 7)) 83990792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 84090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 84190792Sgshapiro macid("{if_name}"), NULL); 84290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 84390792Sgshapiro macid("{if_addr}"), NULL); 84490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 84590792Sgshapiro macid("{if_family}"), NULL); 84664562Sgshapiro } 84738032Speter break; 84838032Speter } 84938032Speter 85038032Speter /* parent -- keep track of children */ 85164562Sgshapiro if (control) 85264562Sgshapiro { 85390792Sgshapiro (void) sm_snprintf(status, sizeof status, 85490792Sgshapiro "control socket server child"); 85590792Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1); 85664562Sgshapiro } 85764562Sgshapiro else 85864562Sgshapiro { 85990792Sgshapiro (void) sm_snprintf(status, sizeof status, 86090792Sgshapiro "SMTP server child for %s", 86190792Sgshapiro anynet_ntoa(&RealHostAddr)); 86290792Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1); 86364562Sgshapiro } 86490792Sgshapiro (void) sm_releasesignal(SIGCHLD); 86538032Speter 86638032Speter /* close the read end of the synchronization pipe */ 86738032Speter if (pipefd[0] != -1) 86864562Sgshapiro { 86938032Speter (void) close(pipefd[0]); 87064562Sgshapiro pipefd[0] = -1; 87164562Sgshapiro } 87238032Speter 87338032Speter /* close the port so that others will hang (for a while) */ 87438032Speter (void) close(t); 87538032Speter 87638032Speter /* release the child by closing the read end of the sync pipe */ 87738032Speter if (pipefd[1] != -1) 87864562Sgshapiro { 87938032Speter (void) close(pipefd[1]); 88064562Sgshapiro pipefd[1] = -1; 88164562Sgshapiro } 88238032Speter } 88390792Sgshapiro if (tTd(15, 2)) 88490792Sgshapiro sm_dprintf("getreq: returning\n"); 88564562Sgshapiro 88690792Sgshapiro#if MILTER 88790792Sgshapiro# if _FFR_MILTER_PERDAEMON 88890792Sgshapiro /* set the filters for this daemon */ 88990792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 89090792Sgshapiro { 89190792Sgshapiro for (i = 0; 89290792Sgshapiro (Daemons[curdaemon].d_inputfilters[i] != NULL && 89390792Sgshapiro i < MAXFILTERS); 89490792Sgshapiro i++) 89590792Sgshapiro { 89690792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 89790792Sgshapiro } 89890792Sgshapiro if (i < MAXFILTERS) 89990792Sgshapiro InputFilters[i] = NULL; 90090792Sgshapiro } 90190792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 90290792Sgshapiro#endif /* MILTER */ 90364562Sgshapiro return &Daemons[curdaemon].d_flags; 90438032Speter} 90590792Sgshapiro 90690792Sgshapiro/* 90790792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 90890792Sgshapiro** 90990792Sgshapiro** Parameters: 91090792Sgshapiro** e -- envelope. 91190792Sgshapiro** 91290792Sgshapiro** Returns: 91390792Sgshapiro** none. 91490792Sgshapiro** 91590792Sgshapiro** Side Effects: 91690792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 91790792Sgshapiro*/ 91890792Sgshapiro 91990792Sgshapirostatic void 92090792Sgshapirogetrequests_checkdiskspace(e) 92190792Sgshapiro ENVELOPE *e; 92290792Sgshapiro{ 92390792Sgshapiro bool logged = false; 92490792Sgshapiro int idx; 92590792Sgshapiro time_t now; 92690792Sgshapiro 92790792Sgshapiro now = curtime(); 92890792Sgshapiro if (now < NextDiskSpaceCheck) 92990792Sgshapiro return; 93090792Sgshapiro 93190792Sgshapiro /* Check if there is available disk space in all queue groups. */ 93290792Sgshapiro if (!enoughdiskspace(0, NULL)) 93390792Sgshapiro { 93490792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 93590792Sgshapiro { 93690792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 93790792Sgshapiro continue; 93890792Sgshapiro 93990792Sgshapiro /* log only if not logged before */ 94090792Sgshapiro if (!logged) 94190792Sgshapiro { 94290792Sgshapiro if (LogLevel > 8) 94390792Sgshapiro sm_syslog(LOG_INFO, NOQID, 94490792Sgshapiro "rejecting new messages: min free: %ld", 94590792Sgshapiro MinBlocksFree); 94690792Sgshapiro sm_setproctitle(true, e, 94790792Sgshapiro "rejecting new messages: min free: %ld", 94890792Sgshapiro MinBlocksFree); 94990792Sgshapiro logged = true; 95090792Sgshapiro } 95190792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 95290792Sgshapiro } 95390792Sgshapiro } 95490792Sgshapiro else 95590792Sgshapiro { 95690792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 95790792Sgshapiro { 95890792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 95990792Sgshapiro continue; 96090792Sgshapiro 96190792Sgshapiro /* log only if not logged before */ 96290792Sgshapiro if (!logged) 96390792Sgshapiro { 96490792Sgshapiro if (LogLevel > 8) 96590792Sgshapiro sm_syslog(LOG_INFO, NOQID, 96690792Sgshapiro "accepting new messages (again)"); 96790792Sgshapiro logged = true; 96890792Sgshapiro } 96990792Sgshapiro 97090792Sgshapiro /* title will be set later */ 97190792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 97290792Sgshapiro } 97390792Sgshapiro } 97490792Sgshapiro 97590792Sgshapiro /* only check disk space once a minute */ 97690792Sgshapiro NextDiskSpaceCheck = now + 60; 97790792Sgshapiro} 97890792Sgshapiro 97990792Sgshapiro/* 98064562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 98138032Speter** 98264562Sgshapiro** Deals with setting all appropriate options. 98338032Speter** 98438032Speter** Parameters: 98564562Sgshapiro** d -- the structure for the daemon to open. 98638032Speter** firsttime -- set if this is the initial open. 98738032Speter** 98838032Speter** Returns: 98938032Speter** Size in bytes of the daemon socket addr. 99038032Speter** 99138032Speter** Side Effects: 99238032Speter** Leaves DaemonSocket set to the open socket. 99338032Speter** Exits if the socket cannot be created. 99438032Speter*/ 99538032Speter 99690792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 99738032Speter 99864562Sgshapirostatic int 99964562Sgshapiroopendaemonsocket(d, firsttime) 100090792Sgshapiro DAEMON_T *d; 100138032Speter bool firsttime; 100238032Speter{ 100338032Speter int on = 1; 100464562Sgshapiro int fdflags; 100564562Sgshapiro SOCKADDR_LEN_T socksize = 0; 100638032Speter int ntries = 0; 100764562Sgshapiro int save_errno; 100838032Speter 100938032Speter if (tTd(15, 2)) 101090792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 101138032Speter 101238032Speter do 101338032Speter { 101438032Speter if (ntries > 0) 101564562Sgshapiro (void) sleep(5); 101664562Sgshapiro if (firsttime || d->d_socket < 0) 101738032Speter { 101890792Sgshapiro#if _FFR_DAEMON_NETUNIX 101990792Sgshapiro# if NETUNIX 102090792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 102190792Sgshapiro { 102290792Sgshapiro int rval; 102390792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 102490792Sgshapiro 102590792Sgshapiro /* if not safe, don't use it */ 102690792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 102790792Sgshapiro RunAsUid, RunAsGid, 102890792Sgshapiro RunAsUserName, sff, 102990792Sgshapiro S_IRUSR|S_IWUSR, NULL); 103090792Sgshapiro if (rval != 0) 103190792Sgshapiro { 103290792Sgshapiro save_errno = errno; 103390792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 103490792Sgshapiro d->d_name, 103590792Sgshapiro d->d_addr.sunix.sun_path); 103690792Sgshapiro goto fail; 103790792Sgshapiro } 103890792Sgshapiro 103990792Sgshapiro /* Don't try to overtake an existing socket */ 104090792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 104190792Sgshapiro } 104290792Sgshapiro# endif /* NETUNIX */ 104390792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */ 104464562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 104564562Sgshapiro SOCK_STREAM, 0); 104664562Sgshapiro if (d->d_socket < 0) 104738032Speter { 104864562Sgshapiro save_errno = errno; 104990792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 105090792Sgshapiro d->d_name); 105190792Sgshapiro fail: 105290792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 105390792Sgshapiro (!transienterror(save_errno) || 105490792Sgshapiro ntries >= MAXOPENTRIES - 1)) 105590792Sgshapiro { 105690792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 105790792Sgshapiro d->d_name); 105890792Sgshapiro setbitn(D_DISABLE, d->d_flags); 105990792Sgshapiro d->d_socket = -1; 106090792Sgshapiro return -1; 106190792Sgshapiro } 106238032Speter severe: 106338032Speter if (LogLevel > 0) 106438032Speter sm_syslog(LOG_ALERT, NOQID, 106590792Sgshapiro "daemon %s: problem creating SMTP socket", 106690792Sgshapiro d->d_name); 106764562Sgshapiro d->d_socket = -1; 106838032Speter continue; 106938032Speter } 107038032Speter 107138032Speter /* turn on network debugging? */ 107238032Speter if (tTd(15, 101)) 107364562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 107438032Speter SO_DEBUG, (char *)&on, 107538032Speter sizeof on); 107638032Speter 107764562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 107838032Speter SO_REUSEADDR, (char *)&on, sizeof on); 107964562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 108038032Speter SO_KEEPALIVE, (char *)&on, sizeof on); 108138032Speter 108290792Sgshapiro#ifdef SO_RCVBUF 108364562Sgshapiro if (d->d_tcprcvbufsize > 0) 108438032Speter { 108564562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 108638032Speter SO_RCVBUF, 108764562Sgshapiro (char *) &d->d_tcprcvbufsize, 108864562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 108964562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 109038032Speter } 109190792Sgshapiro#endif /* SO_RCVBUF */ 109290792Sgshapiro#ifdef SO_SNDBUF 109364562Sgshapiro if (d->d_tcpsndbufsize > 0) 109464562Sgshapiro { 109564562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 109664562Sgshapiro SO_SNDBUF, 109764562Sgshapiro (char *) &d->d_tcpsndbufsize, 109864562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 109964562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 110064562Sgshapiro } 110190792Sgshapiro#endif /* SO_SNDBUF */ 110238032Speter 110364562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 110464562Sgshapiro fcntl(d->d_socket, F_SETFD, 110564562Sgshapiro fdflags | FD_CLOEXEC) == -1) 110638032Speter { 110764562Sgshapiro save_errno = errno; 110864562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 110964562Sgshapiro d->d_name, 111064562Sgshapiro fdflags == -1 ? "get" : "set", 111190792Sgshapiro sm_errstring(save_errno)); 111264562Sgshapiro (void) close(d->d_socket); 111364562Sgshapiro goto severe; 111464562Sgshapiro } 111564562Sgshapiro 111664562Sgshapiro switch (d->d_addr.sa.sa_family) 111764562Sgshapiro { 111890792Sgshapiro#if _FFR_DAEMON_NETUNIX 111990792Sgshapiro# ifdef NETUNIX 112090792Sgshapiro case AF_UNIX: 112190792Sgshapiro socksize = sizeof d->d_addr.sunix; 112290792Sgshapiro break; 112390792Sgshapiro# endif /* NETUNIX */ 112490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 112590792Sgshapiro#if NETINET 112638032Speter case AF_INET: 112764562Sgshapiro socksize = sizeof d->d_addr.sin; 112838032Speter break; 112990792Sgshapiro#endif /* NETINET */ 113038032Speter 113190792Sgshapiro#if NETINET6 113264562Sgshapiro case AF_INET6: 113364562Sgshapiro socksize = sizeof d->d_addr.sin6; 113464562Sgshapiro break; 113590792Sgshapiro#endif /* NETINET6 */ 113664562Sgshapiro 113790792Sgshapiro#if NETISO 113838032Speter case AF_ISO: 113964562Sgshapiro socksize = sizeof d->d_addr.siso; 114038032Speter break; 114190792Sgshapiro#endif /* NETISO */ 114238032Speter 114338032Speter default: 114464562Sgshapiro socksize = sizeof d->d_addr; 114538032Speter break; 114638032Speter } 114738032Speter 114864562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 114938032Speter { 115038032Speter /* probably another daemon already */ 115164562Sgshapiro save_errno = errno; 115264562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 115364562Sgshapiro d->d_name); 115464562Sgshapiro (void) close(d->d_socket); 115590792Sgshapiro goto fail; 115638032Speter } 115738032Speter } 115864562Sgshapiro if (!firsttime && 115964562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 116038032Speter { 116164562Sgshapiro save_errno = errno; 116264562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 116364562Sgshapiro d->d_name); 116464562Sgshapiro (void) close(d->d_socket); 116538032Speter goto severe; 116638032Speter } 116738032Speter return socksize; 116864562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 116964562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 117064562Sgshapiro d->d_name); 117164562Sgshapiro /* NOTREACHED */ 117238032Speter return -1; /* avoid compiler warning on IRIX */ 117338032Speter} 117490792Sgshapiro/* 117564562Sgshapiro** SETUPDAEMON -- setup socket for daemon 117664562Sgshapiro** 117764562Sgshapiro** Parameters: 117864562Sgshapiro** daemonaddr -- socket for daemon 117964562Sgshapiro** 118064562Sgshapiro** Returns: 118164562Sgshapiro** port number on which daemon should run 118264562Sgshapiro** 118364562Sgshapiro*/ 118490792Sgshapiro 118590792Sgshapirostatic unsigned short 118664562Sgshapirosetupdaemon(daemonaddr) 118764562Sgshapiro SOCKADDR *daemonaddr; 118864562Sgshapiro{ 118990792Sgshapiro unsigned short port; 119064562Sgshapiro 119164562Sgshapiro /* 119264562Sgshapiro ** Set up the address for the mailer. 119364562Sgshapiro */ 119464562Sgshapiro 119564562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 119664562Sgshapiro { 119764562Sgshapiro memset(daemonaddr, '\0', sizeof *daemonaddr); 119890792Sgshapiro#if NETINET 119964562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 120090792Sgshapiro#endif /* NETINET */ 120164562Sgshapiro } 120264562Sgshapiro 120364562Sgshapiro switch (daemonaddr->sa.sa_family) 120464562Sgshapiro { 120590792Sgshapiro#if NETINET 120664562Sgshapiro case AF_INET: 120764562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 120864562Sgshapiro daemonaddr->sin.sin_addr.s_addr = INADDR_ANY; 120964562Sgshapiro port = daemonaddr->sin.sin_port; 121064562Sgshapiro break; 121190792Sgshapiro#endif /* NETINET */ 121264562Sgshapiro 121390792Sgshapiro#if NETINET6 121464562Sgshapiro case AF_INET6: 121564562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 121664562Sgshapiro daemonaddr->sin6.sin6_addr = in6addr_any; 121764562Sgshapiro port = daemonaddr->sin6.sin6_port; 121864562Sgshapiro break; 121990792Sgshapiro#endif /* NETINET6 */ 122064562Sgshapiro 122164562Sgshapiro default: 122264562Sgshapiro /* unknown protocol */ 122364562Sgshapiro port = 0; 122464562Sgshapiro break; 122564562Sgshapiro } 122664562Sgshapiro if (port == 0) 122764562Sgshapiro { 122890792Sgshapiro#ifdef NO_GETSERVBYNAME 122964562Sgshapiro port = htons(25); 123090792Sgshapiro#else /* NO_GETSERVBYNAME */ 123164562Sgshapiro { 123264562Sgshapiro register struct servent *sp; 123364562Sgshapiro 123464562Sgshapiro sp = getservbyname("smtp", "tcp"); 123564562Sgshapiro if (sp == NULL) 123664562Sgshapiro { 123764562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 123864562Sgshapiro port = htons(25); 123964562Sgshapiro } 124064562Sgshapiro else 124164562Sgshapiro port = sp->s_port; 124264562Sgshapiro } 124390792Sgshapiro#endif /* NO_GETSERVBYNAME */ 124464562Sgshapiro } 124564562Sgshapiro 124664562Sgshapiro switch (daemonaddr->sa.sa_family) 124764562Sgshapiro { 124890792Sgshapiro#if NETINET 124964562Sgshapiro case AF_INET: 125064562Sgshapiro daemonaddr->sin.sin_port = port; 125164562Sgshapiro break; 125290792Sgshapiro#endif /* NETINET */ 125364562Sgshapiro 125490792Sgshapiro#if NETINET6 125564562Sgshapiro case AF_INET6: 125664562Sgshapiro daemonaddr->sin6.sin6_port = port; 125764562Sgshapiro break; 125890792Sgshapiro#endif /* NETINET6 */ 125964562Sgshapiro 126064562Sgshapiro default: 126164562Sgshapiro /* unknown protocol */ 126264562Sgshapiro break; 126364562Sgshapiro } 126490792Sgshapiro return port; 126564562Sgshapiro} 126690792Sgshapiro/* 126738032Speter** CLRDAEMON -- reset the daemon connection 126838032Speter** 126938032Speter** Parameters: 127038032Speter** none. 127138032Speter** 127238032Speter** Returns: 127338032Speter** none. 127438032Speter** 127538032Speter** Side Effects: 127638032Speter** releases any resources used by the passive daemon. 127738032Speter*/ 127838032Speter 127938032Spetervoid 128038032Speterclrdaemon() 128138032Speter{ 128264562Sgshapiro int i; 128364562Sgshapiro 128490792Sgshapiro for (i = 0; i < NDaemons; i++) 128564562Sgshapiro { 128664562Sgshapiro if (Daemons[i].d_socket >= 0) 128764562Sgshapiro (void) close(Daemons[i].d_socket); 128864562Sgshapiro Daemons[i].d_socket = -1; 128964562Sgshapiro } 129038032Speter} 129190792Sgshapiro 129290792Sgshapiro/* 129390792Sgshapiro** GETMODIFIERS -- get modifier flags 129490792Sgshapiro** 129590792Sgshapiro** Parameters: 129690792Sgshapiro** v -- the modifiers (input text line). 129790792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 129890792Sgshapiro** 129990792Sgshapiro** Returns: 130090792Sgshapiro** (xallocat()ed) string representation of modifiers. 130190792Sgshapiro** 130290792Sgshapiro** Side Effects: 130390792Sgshapiro** fills in modifiers. 130490792Sgshapiro*/ 130590792Sgshapiro 130690792Sgshapirochar * 130790792Sgshapirogetmodifiers(v, modifiers) 130890792Sgshapiro char *v; 130990792Sgshapiro BITMAP256 modifiers; 131090792Sgshapiro{ 131190792Sgshapiro int l; 131290792Sgshapiro char *h, *f, *flags; 131390792Sgshapiro 131490792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 131590792Sgshapiro l = 3 * strlen(v) + 3; 131690792Sgshapiro 131790792Sgshapiro /* is someone joking? */ 131890792Sgshapiro if (l < 0 || l > 256) 131990792Sgshapiro { 132090792Sgshapiro if (LogLevel > 2) 132190792Sgshapiro sm_syslog(LOG_ERR, NOQID, 132290792Sgshapiro "getmodifiers too long, ignored"); 132390792Sgshapiro return NULL; 132490792Sgshapiro } 132590792Sgshapiro flags = xalloc(l); 132690792Sgshapiro f = flags; 132790792Sgshapiro clrbitmap(modifiers); 132890792Sgshapiro for (h = v; *h != '\0'; h++) 132990792Sgshapiro { 133090792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 133190792Sgshapiro { 133290792Sgshapiro setbitn(*h, modifiers); 133390792Sgshapiro if (flags != f) 133490792Sgshapiro *flags++ = ' '; 133590792Sgshapiro *flags++ = *h; 133690792Sgshapiro if (isupper(*h)) 133790792Sgshapiro *flags++ = *h; 133890792Sgshapiro } 133990792Sgshapiro } 134090792Sgshapiro *flags++ = '\0'; 134190792Sgshapiro return f; 134290792Sgshapiro} 134390792Sgshapiro 134490792Sgshapiro/* 134590792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 134690792Sgshapiro** 134790792Sgshapiro** Parameters: 134890792Sgshapiro** flag -- the flag to test. 134990792Sgshapiro** 135090792Sgshapiro** Returns: 135190792Sgshapiro** true iff all daemons have set flag. 135290792Sgshapiro*/ 135390792Sgshapiro 135490792Sgshapirobool 135590792Sgshapirochkdaemonmodifiers(flag) 135690792Sgshapiro int flag; 135790792Sgshapiro{ 135890792Sgshapiro int i; 135990792Sgshapiro 136090792Sgshapiro for (i = 0; i < NDaemons; i++) 136190792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 136290792Sgshapiro return false; 136390792Sgshapiro return true; 136490792Sgshapiro} 136590792Sgshapiro 136690792Sgshapiro/* 136764562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 136838032Speter** 136938032Speter** Parameters: 137038032Speter** p -- the options line. 137164562Sgshapiro** d -- the daemon structure to fill in. 137238032Speter** 137338032Speter** Returns: 137438032Speter** none. 137538032Speter*/ 137638032Speter 137764562Sgshapirostatic void 137864562Sgshapirosetsockaddroptions(p, d) 137938032Speter register char *p; 138090792Sgshapiro DAEMON_T *d; 138138032Speter{ 138290792Sgshapiro#if NETISO 138371345Sgshapiro short portno; 138490792Sgshapiro#endif /* NETISO */ 138571345Sgshapiro char *port = NULL; 138671345Sgshapiro char *addr = NULL; 138738032Speter 138890792Sgshapiro#if NETINET 138964562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 139064562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 139190792Sgshapiro#endif /* NETINET */ 139264562Sgshapiro 139338032Speter while (p != NULL) 139438032Speter { 139538032Speter register char *f; 139638032Speter register char *v; 139738032Speter 139838032Speter while (isascii(*p) && isspace(*p)) 139938032Speter p++; 140038032Speter if (*p == '\0') 140138032Speter break; 140238032Speter f = p; 140338032Speter p = strchr(p, ','); 140438032Speter if (p != NULL) 140538032Speter *p++ = '\0'; 140638032Speter v = strchr(f, '='); 140738032Speter if (v == NULL) 140838032Speter continue; 140938032Speter while (isascii(*++v) && isspace(*v)) 141038032Speter continue; 141138032Speter if (isascii(*f) && islower(*f)) 141238032Speter *f = toupper(*f); 141338032Speter 141438032Speter switch (*f) 141538032Speter { 141638032Speter case 'F': /* address family */ 141738032Speter if (isascii(*v) && isdigit(*v)) 141864562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 141990792Sgshapiro#if _FFR_DAEMON_NETUNIX 142090792Sgshapiro# ifdef NETUNIX 142190792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 142290792Sgshapiro sm_strcasecmp(v, "local") == 0) 142390792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 142490792Sgshapiro# endif /* NETUNIX */ 142590792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 142690792Sgshapiro#if NETINET 142790792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 142864562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 142990792Sgshapiro#endif /* NETINET */ 143090792Sgshapiro#if NETINET6 143190792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 143264562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 143390792Sgshapiro#endif /* NETINET6 */ 143490792Sgshapiro#if NETISO 143590792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 143664562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 143790792Sgshapiro#endif /* NETISO */ 143890792Sgshapiro#if NETNS 143990792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 144064562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 144190792Sgshapiro#endif /* NETNS */ 144290792Sgshapiro#if NETX25 144390792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 144464562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 144590792Sgshapiro#endif /* NETX25 */ 144638032Speter else 144764562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 144864562Sgshapiro v); 144938032Speter break; 145038032Speter 145138032Speter case 'A': /* address */ 145271345Sgshapiro addr = v; 145338032Speter break; 145438032Speter 145590792Sgshapiro#if MILTER 145690792Sgshapiro# if _FFR_MILTER_PERDAEMON 145790792Sgshapiro case 'I': 145890792Sgshapiro d->d_inputfilterlist = v; 145990792Sgshapiro break; 146090792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 146190792Sgshapiro#endif /* MILTER */ 146290792Sgshapiro 146338032Speter case 'P': /* port */ 146471345Sgshapiro port = v; 146538032Speter break; 146638032Speter 146738032Speter case 'L': /* listen queue size */ 146864562Sgshapiro d->d_listenqueue = atoi(v); 146938032Speter break; 147038032Speter 147164562Sgshapiro case 'M': /* modifiers (flags) */ 147290792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 147364562Sgshapiro break; 147464562Sgshapiro 147538032Speter case 'S': /* send buffer size */ 147664562Sgshapiro d->d_tcpsndbufsize = atoi(v); 147738032Speter break; 147838032Speter 147938032Speter case 'R': /* receive buffer size */ 148064562Sgshapiro d->d_tcprcvbufsize = atoi(v); 148138032Speter break; 148238032Speter 148364562Sgshapiro case 'N': /* name */ 148464562Sgshapiro d->d_name = v; 148564562Sgshapiro break; 148664562Sgshapiro 148738032Speter default: 148864562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 148964562Sgshapiro f); 149038032Speter } 149138032Speter } 149271345Sgshapiro 149371345Sgshapiro /* Check addr and port after finding family */ 149471345Sgshapiro if (addr != NULL) 149571345Sgshapiro { 149671345Sgshapiro switch (d->d_addr.sa.sa_family) 149771345Sgshapiro { 149890792Sgshapiro#if _FFR_DAEMON_NETUNIX 149990792Sgshapiro# if NETUNIX 150090792Sgshapiro case AF_UNIX: 150190792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 150290792Sgshapiro { 150390792Sgshapiro errno = ENAMETOOLONG; 150490792Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %d", 150590792Sgshapiro addr, sizeof(d->d_addr.sunix.sun_path)); 150690792Sgshapiro break; 150790792Sgshapiro } 150890792Sgshapiro 150990792Sgshapiro /* file safety check done in opendaemonsocket() */ 151090792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 151190792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 151290792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 151390792Sgshapiro addr, 151490792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 151590792Sgshapiro break; 151690792Sgshapiro# endif /* NETUNIX */ 151790792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 151890792Sgshapiro#if NETINET 151971345Sgshapiro case AF_INET: 152071345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 152190792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 152290792Sgshapiro == INADDR_NONE)) 152371345Sgshapiro { 152471345Sgshapiro register struct hostent *hp; 152571345Sgshapiro 152671345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 152771345Sgshapiro if (hp == NULL) 152871345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 152971345Sgshapiro addr); 153071345Sgshapiro else 153171345Sgshapiro { 153271345Sgshapiro while (*(hp->h_addr_list) != NULL && 153371345Sgshapiro hp->h_addrtype != AF_INET) 153471345Sgshapiro hp->h_addr_list++; 153571345Sgshapiro if (*(hp->h_addr_list) == NULL) 153671345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 153771345Sgshapiro addr); 153871345Sgshapiro else 153971345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 154071345Sgshapiro *(hp->h_addr_list), 154171345Sgshapiro INADDRSZ); 154290792Sgshapiro# if NETINET6 154371345Sgshapiro freehostent(hp); 154471345Sgshapiro hp = NULL; 154590792Sgshapiro# endif /* NETINET6 */ 154671345Sgshapiro } 154771345Sgshapiro } 154871345Sgshapiro break; 154990792Sgshapiro#endif /* NETINET */ 155071345Sgshapiro 155190792Sgshapiro#if NETINET6 155271345Sgshapiro case AF_INET6: 155390792Sgshapiro if (anynet_pton(AF_INET6, addr, 155490792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 155571345Sgshapiro { 155671345Sgshapiro register struct hostent *hp; 155771345Sgshapiro 155871345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 155971345Sgshapiro if (hp == NULL) 156071345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 156171345Sgshapiro addr); 156271345Sgshapiro else 156371345Sgshapiro { 156471345Sgshapiro while (*(hp->h_addr_list) != NULL && 156571345Sgshapiro hp->h_addrtype != AF_INET6) 156671345Sgshapiro hp->h_addr_list++; 156771345Sgshapiro if (*(hp->h_addr_list) == NULL) 156871345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 156971345Sgshapiro addr); 157071345Sgshapiro else 157171345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 157271345Sgshapiro *(hp->h_addr_list), 157371345Sgshapiro IN6ADDRSZ); 157471345Sgshapiro freehostent(hp); 157571345Sgshapiro hp = NULL; 157671345Sgshapiro } 157771345Sgshapiro } 157871345Sgshapiro break; 157990792Sgshapiro#endif /* NETINET6 */ 158071345Sgshapiro 158171345Sgshapiro default: 158271345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 158371345Sgshapiro d->d_addr.sa.sa_family); 158471345Sgshapiro break; 158571345Sgshapiro } 158671345Sgshapiro } 158771345Sgshapiro 158871345Sgshapiro if (port != NULL) 158971345Sgshapiro { 159071345Sgshapiro switch (d->d_addr.sa.sa_family) 159171345Sgshapiro { 159290792Sgshapiro#if NETINET 159371345Sgshapiro case AF_INET: 159471345Sgshapiro if (isascii(*port) && isdigit(*port)) 159590792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 159690792Sgshapiro atoi((const char *) port)); 159771345Sgshapiro else 159871345Sgshapiro { 159990792Sgshapiro# ifdef NO_GETSERVBYNAME 160071345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 160171345Sgshapiro port); 160290792Sgshapiro# else /* NO_GETSERVBYNAME */ 160371345Sgshapiro register struct servent *sp; 160471345Sgshapiro 160571345Sgshapiro sp = getservbyname(port, "tcp"); 160671345Sgshapiro if (sp == NULL) 160771345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 160871345Sgshapiro port); 160971345Sgshapiro else 161071345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 161190792Sgshapiro# endif /* NO_GETSERVBYNAME */ 161271345Sgshapiro } 161371345Sgshapiro break; 161490792Sgshapiro#endif /* NETINET */ 161571345Sgshapiro 161690792Sgshapiro#if NETINET6 161771345Sgshapiro case AF_INET6: 161871345Sgshapiro if (isascii(*port) && isdigit(*port)) 161990792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 162090792Sgshapiro atoi(port)); 162171345Sgshapiro else 162271345Sgshapiro { 162390792Sgshapiro# ifdef NO_GETSERVBYNAME 162471345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 162571345Sgshapiro port); 162690792Sgshapiro# else /* NO_GETSERVBYNAME */ 162771345Sgshapiro register struct servent *sp; 162871345Sgshapiro 162971345Sgshapiro sp = getservbyname(port, "tcp"); 163071345Sgshapiro if (sp == NULL) 163171345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 163271345Sgshapiro port); 163371345Sgshapiro else 163471345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 163590792Sgshapiro# endif /* NO_GETSERVBYNAME */ 163671345Sgshapiro } 163771345Sgshapiro break; 163890792Sgshapiro#endif /* NETINET6 */ 163971345Sgshapiro 164090792Sgshapiro#if NETISO 164171345Sgshapiro case AF_ISO: 164271345Sgshapiro /* assume two byte transport selector */ 164371345Sgshapiro if (isascii(*port) && isdigit(*port)) 164490792Sgshapiro portno = htons((unsigned short) atoi(port)); 164571345Sgshapiro else 164671345Sgshapiro { 164790792Sgshapiro# ifdef NO_GETSERVBYNAME 164871345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 164971345Sgshapiro port); 165090792Sgshapiro# else /* NO_GETSERVBYNAME */ 165171345Sgshapiro register struct servent *sp; 165271345Sgshapiro 165371345Sgshapiro sp = getservbyname(port, "tcp"); 165471345Sgshapiro if (sp == NULL) 165571345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 165671345Sgshapiro port); 165771345Sgshapiro else 165871345Sgshapiro portno = sp->s_port; 165990792Sgshapiro# endif /* NO_GETSERVBYNAME */ 166071345Sgshapiro } 166171345Sgshapiro memmove(TSEL(&d->d_addr.siso), 166271345Sgshapiro (char *) &portno, 2); 166371345Sgshapiro break; 166490792Sgshapiro#endif /* NETISO */ 166571345Sgshapiro 166671345Sgshapiro default: 166771345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 166871345Sgshapiro d->d_addr.sa.sa_family); 166971345Sgshapiro break; 167071345Sgshapiro } 167171345Sgshapiro } 167238032Speter} 167390792Sgshapiro/* 167464562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 167538032Speter** 167638032Speter** Parameters: 167764562Sgshapiro** p -- the options line. 167864562Sgshapiro** 167964562Sgshapiro** Returns: 168090792Sgshapiro** true if successful, false otherwise. 168190792Sgshapiro** 168290792Sgshapiro** Side Effects: 168390792Sgshapiro** increments number of daemons. 168464562Sgshapiro*/ 168564562Sgshapiro 168690792Sgshapiro#define DEF_LISTENQUEUE 10 168790792Sgshapiro 168864562Sgshapirobool 168964562Sgshapirosetdaemonoptions(p) 169064562Sgshapiro register char *p; 169164562Sgshapiro{ 169290792Sgshapiro if (NDaemons >= MAXDAEMONS) 169390792Sgshapiro return false; 169490792Sgshapiro Daemons[NDaemons].d_socket = -1; 169590792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 169690792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 169790792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 169864562Sgshapiro 169990792Sgshapiro#if MILTER 170090792Sgshapiro# if _FFR_MILTER_PERDAEMON 170190792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 170290792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 170390792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 170490792Sgshapiro#endif /* MILTER */ 170590792Sgshapiro 170690792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 170790792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 170864562Sgshapiro else 170964562Sgshapiro { 171064562Sgshapiro char num[30]; 171164562Sgshapiro 171290792Sgshapiro (void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons); 171390792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 171464562Sgshapiro } 171564562Sgshapiro 171664562Sgshapiro if (tTd(37, 1)) 171764562Sgshapiro { 171890792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 171990792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[NDaemons].d_flags)) 172090792Sgshapiro sm_dprintf("ETRNONLY "); 172190792Sgshapiro if (bitnset(D_NOETRN, Daemons[NDaemons].d_flags)) 172290792Sgshapiro sm_dprintf("NOETRN "); 172390792Sgshapiro sm_dprintf("\n"); 172464562Sgshapiro } 172590792Sgshapiro ++NDaemons; 172690792Sgshapiro return true; 172764562Sgshapiro} 172890792Sgshapiro/* 172964562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 173064562Sgshapiro** 173164562Sgshapiro** Parameters: 173264562Sgshapiro** none 173364562Sgshapiro** 173464562Sgshapiro** Returns: 173564562Sgshapiro** none 173664562Sgshapiro** 173764562Sgshapiro** Side Effects: 173864562Sgshapiro** initializes structure for one daemon. 173964562Sgshapiro*/ 174090792Sgshapiro 174164562Sgshapirovoid 174264562Sgshapiroinitdaemon() 174364562Sgshapiro{ 174490792Sgshapiro if (NDaemons == 0) 174564562Sgshapiro { 174690792Sgshapiro Daemons[NDaemons].d_socket = -1; 174790792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 174890792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 174990792Sgshapiro NDaemons = 1; 175064562Sgshapiro } 175164562Sgshapiro} 175290792Sgshapiro/* 175364562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 175464562Sgshapiro** 175564562Sgshapiro** Parameters: 175664562Sgshapiro** p -- the options line. 175764562Sgshapiro** 175864562Sgshapiro** Returns: 175964562Sgshapiro** none. 176064562Sgshapiro*/ 176164562Sgshapiro 176290792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 176364562Sgshapiro 176464562Sgshapirovoid 176564562Sgshapirosetclientoptions(p) 176664562Sgshapiro register char *p; 176764562Sgshapiro{ 176890792Sgshapiro int family; 176990792Sgshapiro DAEMON_T d; 177064562Sgshapiro 177164562Sgshapiro memset(&d, '\0', sizeof d); 177264562Sgshapiro setsockaddroptions(p, &d); 177364562Sgshapiro 177464562Sgshapiro /* grab what we need */ 177590792Sgshapiro family = d.d_addr.sa.sa_family; 177690792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 177790792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 177890792Sgshapiro if (d.d_name != NULL) 177990792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 178064562Sgshapiro else 178190792Sgshapiro { 178290792Sgshapiro char num[30]; 178390792Sgshapiro 178490792Sgshapiro (void) sm_snprintf(num, sizeof num, "Client%d", family); 178590792Sgshapiro ClientSettings[family].d_name = newstr(num); 178690792Sgshapiro } 178764562Sgshapiro} 178890792Sgshapiro/* 178964562Sgshapiro** ADDR_FAMILY -- determine address family from address 179064562Sgshapiro** 179164562Sgshapiro** Parameters: 179264562Sgshapiro** addr -- the string representation of the address 179364562Sgshapiro** 179464562Sgshapiro** Returns: 179564562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 179664562Sgshapiro** 179764562Sgshapiro** Side Effects: 179864562Sgshapiro** none. 179964562Sgshapiro*/ 180064562Sgshapiro 180164562Sgshapirostatic int 180264562Sgshapiroaddr_family(addr) 180364562Sgshapiro char *addr; 180464562Sgshapiro{ 180590792Sgshapiro#if NETINET6 180664562Sgshapiro SOCKADDR clt_addr; 180790792Sgshapiro#endif /* NETINET6 */ 180864562Sgshapiro 180990792Sgshapiro#if NETINET 181064562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 181164562Sgshapiro { 181264562Sgshapiro if (tTd(16, 9)) 181390792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 181464562Sgshapiro return AF_INET; 181564562Sgshapiro } 181690792Sgshapiro#endif /* NETINET */ 181790792Sgshapiro#if NETINET6 181890792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 181964562Sgshapiro { 182064562Sgshapiro if (tTd(16, 9)) 182190792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 182264562Sgshapiro return AF_INET6; 182364562Sgshapiro } 182490792Sgshapiro#endif /* NETINET6 */ 182590792Sgshapiro#if _FFR_DAEMON_NETUNIX 182690792Sgshapiro# if NETUNIX 182790792Sgshapiro if (*addr == '/') 182890792Sgshapiro { 182990792Sgshapiro if (tTd(16, 9)) 183090792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 183190792Sgshapiro return AF_UNIX; 183290792Sgshapiro } 183390792Sgshapiro# endif /* NETUNIX */ 183490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 183564562Sgshapiro if (tTd(16, 9)) 183690792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 183764562Sgshapiro return AF_UNSPEC; 183864562Sgshapiro} 183990792Sgshapiro 184090792Sgshapiro/* 184190792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 184290792Sgshapiro** 184390792Sgshapiro** Parameters: 184490792Sgshapiro** flag -- the flag to test. 184590792Sgshapiro** 184690792Sgshapiro** Returns: 184790792Sgshapiro** true iff all configured clients have set the flag. 184890792Sgshapiro*/ 184990792Sgshapiro 185090792Sgshapirobool 185190792Sgshapirochkclientmodifiers(flag) 185290792Sgshapiro int flag; 185390792Sgshapiro{ 185490792Sgshapiro int i; 185590792Sgshapiro bool flagisset; 185690792Sgshapiro 185790792Sgshapiro flagisset = false; 185890792Sgshapiro for (i = 0; i < AF_MAX; i++) 185990792Sgshapiro { 186090792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 186190792Sgshapiro { 186290792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 186390792Sgshapiro return false; 186490792Sgshapiro flagisset = true; 186590792Sgshapiro } 186690792Sgshapiro } 186790792Sgshapiro return flagisset; 186890792Sgshapiro} 186990792Sgshapiro 187090792Sgshapiro#if MILTER 187190792Sgshapiro# if _FFR_MILTER_PERDAEMON 187290792Sgshapiro/* 187390792Sgshapiro** SETUP_DAEMON_FILTERS -- Parse per-socket filters 187490792Sgshapiro** 187590792Sgshapiro** Parameters: 187690792Sgshapiro** none 187790792Sgshapiro** 187890792Sgshapiro** Returns: 187990792Sgshapiro** none 188090792Sgshapiro*/ 188190792Sgshapiro 188290792Sgshapirovoid 188390792Sgshapirosetup_daemon_milters() 188490792Sgshapiro{ 188590792Sgshapiro int idx; 188690792Sgshapiro 188790792Sgshapiro if (OpMode == MD_SMTP) 188890792Sgshapiro { 188990792Sgshapiro /* no need to configure the daemons */ 189090792Sgshapiro return; 189190792Sgshapiro } 189290792Sgshapiro 189390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 189490792Sgshapiro { 189590792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 189690792Sgshapiro { 189790792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 189890792Sgshapiro Daemons[idx].d_inputfilters, 189990792Sgshapiro MAXFILTERS); 190090792Sgshapiro } 190190792Sgshapiro } 190290792Sgshapiro} 190390792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 190490792Sgshapiro#endif /* MILTER */ 190590792Sgshapiro/* 190664562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 190764562Sgshapiro** 190864562Sgshapiro** Parameters: 190938032Speter** host -- the name of the host. 191038032Speter** port -- the port number to connect to. 191138032Speter** mci -- a pointer to the mail connection information 191238032Speter** structure to be filled in. 191338032Speter** e -- the current envelope. 191490792Sgshapiro** enough -- time at which to stop further connection attempts. 191590792Sgshapiro** (0 means no limit) 191638032Speter** 191738032Speter** Returns: 191838032Speter** An exit code telling whether the connection could be 191938032Speter** made and if not why not. 192038032Speter** 192138032Speter** Side Effects: 192238032Speter** none. 192338032Speter*/ 192438032Speter 192538032Speterstatic jmp_buf CtxConnectTimeout; 192638032Speter 192738032SpeterSOCKADDR CurHostAddr; /* address of current host */ 192838032Speter 192938032Speterint 193090792Sgshapiromakeconnection(host, port, mci, e, enough) 193138032Speter char *host; 193290792Sgshapiro volatile unsigned int port; 193338032Speter register MCI *mci; 193438032Speter ENVELOPE *e; 193590792Sgshapiro time_t enough; 193638032Speter{ 193738032Speter register volatile int addrno = 0; 193890792Sgshapiro volatile int s; 193990792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 194038032Speter SOCKADDR addr; 194164562Sgshapiro SOCKADDR clt_addr; 194264562Sgshapiro int save_errno = 0; 194364562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 194438032Speter volatile bool firstconnect; 194590792Sgshapiro SM_EVENT *volatile ev = NULL; 194690792Sgshapiro#if NETINET6 194790792Sgshapiro volatile bool v6found = false; 194890792Sgshapiro#endif /* NETINET6 */ 194964562Sgshapiro volatile int family = InetMode; 195064562Sgshapiro SOCKADDR_LEN_T len; 195164562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 195264562Sgshapiro volatile bool clt_bind; 195364562Sgshapiro BITMAP256 d_flags; 195464562Sgshapiro char *p; 195564562Sgshapiro extern ENVELOPE BlankEnvelope; 195638032Speter 195790792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 195864562Sgshapiro clrbitmap(d_flags); 195990792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 196064562Sgshapiro { 196164562Sgshapiro for (; *p != '\0'; p++) 196264562Sgshapiro { 196364562Sgshapiro if (!(isascii(*p) && isspace(*p))) 196471345Sgshapiro setbitn(bitidx(*p), d_flags); 196564562Sgshapiro } 196664562Sgshapiro } 196764562Sgshapiro 196890792Sgshapiro#if NETINET6 196964562Sgshapiro v4retry: 197090792Sgshapiro#endif /* NETINET6 */ 197190792Sgshapiro clt_bind = false; 197264562Sgshapiro 197364562Sgshapiro /* Set up the address for outgoing connection. */ 197464562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 197590792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 197673188Sgshapiro *p != '\0') 197764562Sgshapiro { 197890792Sgshapiro#if NETINET6 197964562Sgshapiro char p6[INET6_ADDRSTRLEN]; 198090792Sgshapiro#endif /* NETINET6 */ 198164562Sgshapiro 198264562Sgshapiro memset(&clt_addr, '\0', sizeof clt_addr); 198364562Sgshapiro 198464562Sgshapiro /* infer the address family from the address itself */ 198564562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 198664562Sgshapiro switch (clt_addr.sa.sa_family) 198764562Sgshapiro { 198890792Sgshapiro#if NETINET 198964562Sgshapiro case AF_INET: 199073188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 199173188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 199273188Sgshapiro clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK) 199364562Sgshapiro { 199490792Sgshapiro clt_bind = true; 199564562Sgshapiro socksize = sizeof (struct sockaddr_in); 199664562Sgshapiro } 199764562Sgshapiro break; 199890792Sgshapiro#endif /* NETINET */ 199964562Sgshapiro 200090792Sgshapiro#if NETINET6 200164562Sgshapiro case AF_INET6: 200264562Sgshapiro if (inet_addr(p) != INADDR_NONE) 200390792Sgshapiro (void) sm_snprintf(p6, sizeof p6, 200490792Sgshapiro "IPv6:::ffff:%s", p); 200564562Sgshapiro else 200690792Sgshapiro (void) sm_strlcpy(p6, p, sizeof p6); 200790792Sgshapiro if (anynet_pton(AF_INET6, p6, 200890792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 200973188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 201064562Sgshapiro { 201190792Sgshapiro clt_bind = true; 201264562Sgshapiro socksize = sizeof (struct sockaddr_in6); 201364562Sgshapiro } 201464562Sgshapiro break; 201590792Sgshapiro#endif /* NETINET6 */ 201664562Sgshapiro 201790792Sgshapiro#if 0 201864562Sgshapiro default: 201964562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 202064562Sgshapiro clt_addr.sa.sa_family); 202164562Sgshapiro break; 202290792Sgshapiro#endif /* 0 */ 202364562Sgshapiro } 202464562Sgshapiro if (clt_bind) 202564562Sgshapiro family = clt_addr.sa.sa_family; 202664562Sgshapiro } 202790792Sgshapiro 202890792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 202990792Sgshapiro if (!clt_bind) 203064562Sgshapiro { 203190792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 203264562Sgshapiro switch (clt_addr.sa.sa_family) 203364562Sgshapiro { 203490792Sgshapiro#if NETINET 203564562Sgshapiro case AF_INET: 203664562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 203764562Sgshapiro clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 203864562Sgshapiro else 203990792Sgshapiro clt_bind = true; 204064562Sgshapiro if (clt_addr.sin.sin_port != 0) 204190792Sgshapiro clt_bind = true; 204264562Sgshapiro socksize = sizeof (struct sockaddr_in); 204364562Sgshapiro break; 204490792Sgshapiro#endif /* NETINET */ 204590792Sgshapiro#if NETINET6 204664562Sgshapiro case AF_INET6: 204764562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 204864562Sgshapiro clt_addr.sin6.sin6_addr = in6addr_any; 204964562Sgshapiro else 205090792Sgshapiro clt_bind = true; 205164562Sgshapiro socksize = sizeof (struct sockaddr_in6); 205264562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 205390792Sgshapiro clt_bind = true; 205464562Sgshapiro break; 205590792Sgshapiro#endif /* NETINET6 */ 205690792Sgshapiro#if NETISO 205764562Sgshapiro case AF_ISO: 205864562Sgshapiro socksize = sizeof clt_addr.siso; 205990792Sgshapiro clt_bind = true; 206064562Sgshapiro break; 206190792Sgshapiro#endif /* NETISO */ 206264562Sgshapiro default: 206364562Sgshapiro break; 206464562Sgshapiro } 206564562Sgshapiro } 206664562Sgshapiro 206738032Speter /* 206838032Speter ** Set up the address for the mailer. 206938032Speter ** Accept "[a.b.c.d]" syntax for host name. 207038032Speter */ 207138032Speter 207273188Sgshapiro SM_SET_H_ERRNO(0); 207338032Speter errno = 0; 207464562Sgshapiro memset(&CurHostAddr, '\0', sizeof CurHostAddr); 207564562Sgshapiro memset(&addr, '\0', sizeof addr); 207638032Speter SmtpPhase = mci->mci_phase = "initial connection"; 207738032Speter CurHostName = host; 207838032Speter 207938032Speter if (host[0] == '[') 208038032Speter { 208164562Sgshapiro p = strchr(host, ']'); 208238032Speter if (p != NULL) 208338032Speter { 208490792Sgshapiro#if NETINET 208564562Sgshapiro unsigned long hid = INADDR_NONE; 208690792Sgshapiro#endif /* NETINET */ 208790792Sgshapiro#if NETINET6 208864562Sgshapiro struct sockaddr_in6 hid6; 208990792Sgshapiro#endif /* NETINET6 */ 209064562Sgshapiro 209138032Speter *p = '\0'; 209290792Sgshapiro#if NETINET6 209364562Sgshapiro memset(&hid6, '\0', sizeof hid6); 209490792Sgshapiro#endif /* NETINET6 */ 209590792Sgshapiro#if NETINET 209664562Sgshapiro if (family == AF_INET && 209764562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 209838032Speter { 209964562Sgshapiro addr.sin.sin_family = AF_INET; 210064562Sgshapiro addr.sin.sin_addr.s_addr = hid; 210164562Sgshapiro } 210264562Sgshapiro else 210390792Sgshapiro#endif /* NETINET */ 210490792Sgshapiro#if NETINET6 210564562Sgshapiro if (family == AF_INET6 && 210690792Sgshapiro anynet_pton(AF_INET6, &host[1], 210790792Sgshapiro &hid6.sin6_addr) == 1) 210864562Sgshapiro { 210964562Sgshapiro addr.sin6.sin6_family = AF_INET6; 211064562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 211164562Sgshapiro } 211264562Sgshapiro else 211390792Sgshapiro#endif /* NETINET6 */ 211464562Sgshapiro { 211538032Speter /* try it as a host name (avoid MX lookup) */ 211664562Sgshapiro hp = sm_gethostbyname(&host[1], family); 211738032Speter if (hp == NULL && p[-1] == '.') 211838032Speter { 211990792Sgshapiro#if NAMED_BIND 212038032Speter int oldopts = _res.options; 212138032Speter 212238032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 212390792Sgshapiro#endif /* NAMED_BIND */ 212438032Speter p[-1] = '\0'; 212564562Sgshapiro hp = sm_gethostbyname(&host[1], 212664562Sgshapiro family); 212738032Speter p[-1] = '.'; 212890792Sgshapiro#if NAMED_BIND 212938032Speter _res.options = oldopts; 213090792Sgshapiro#endif /* NAMED_BIND */ 213138032Speter } 213238032Speter *p = ']'; 213338032Speter goto gothostent; 213438032Speter } 213538032Speter *p = ']'; 213638032Speter } 213738032Speter if (p == NULL) 213838032Speter { 213938032Speter extern char MsgBuf[]; 214038032Speter 214164562Sgshapiro usrerrenh("5.1.2", 214264562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 214364562Sgshapiro host); 214438032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 214564562Sgshapiro errno = EINVAL; 214638032Speter return EX_NOHOST; 214738032Speter } 214838032Speter } 214938032Speter else 215038032Speter { 215138032Speter /* contortion to get around SGI cc complaints */ 215238032Speter { 215364562Sgshapiro p = &host[strlen(host) - 1]; 215464562Sgshapiro hp = sm_gethostbyname(host, family); 215538032Speter if (hp == NULL && *p == '.') 215638032Speter { 215790792Sgshapiro#if NAMED_BIND 215838032Speter int oldopts = _res.options; 215938032Speter 216038032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 216190792Sgshapiro#endif /* NAMED_BIND */ 216238032Speter *p = '\0'; 216364562Sgshapiro hp = sm_gethostbyname(host, family); 216438032Speter *p = '.'; 216590792Sgshapiro#if NAMED_BIND 216638032Speter _res.options = oldopts; 216790792Sgshapiro#endif /* NAMED_BIND */ 216838032Speter } 216938032Speter } 217038032Spetergothostent: 217138032Speter if (hp == NULL) 217238032Speter { 217390792Sgshapiro#if NAMED_BIND 217438032Speter /* check for name server timeouts */ 217590792Sgshapiro# if NETINET6 217690792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 217790792Sgshapiro errno == ETIMEDOUT) 217838032Speter { 217990792Sgshapiro /* 218090792Sgshapiro ** An attempt with family AF_INET may 218190792Sgshapiro ** succeed By skipping the next section 218290792Sgshapiro ** of code, we will try AF_INET before 218390792Sgshapiro ** failing. 218490792Sgshapiro */ 218590792Sgshapiro 218690792Sgshapiro if (tTd(16, 10)) 218790792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 218838032Speter } 218990792Sgshapiro else 219090792Sgshapiro# endif /* NETINET6 */ 219190792Sgshapiro { 219290792Sgshapiro if (errno == ETIMEDOUT || 219390792Sgshapiro h_errno == TRY_AGAIN || 219490792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 219590792Sgshapiro { 219690792Sgshapiro save_errno = errno; 219790792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 219890792Sgshapiro "4.4.3", NULL); 219990792Sgshapiro errno = save_errno; 220090792Sgshapiro return EX_TEMPFAIL; 220190792Sgshapiro } 220290792Sgshapiro } 220390792Sgshapiro#endif /* NAMED_BIND */ 220490792Sgshapiro#if NETINET6 220564562Sgshapiro /* 220664562Sgshapiro ** Try v6 first, then fall back to v4. 220764562Sgshapiro ** If we found a v6 address, but no v4 220864562Sgshapiro ** addresses, then TEMPFAIL. 220964562Sgshapiro */ 221064562Sgshapiro 221164562Sgshapiro if (family == AF_INET6) 221264562Sgshapiro { 221364562Sgshapiro family = AF_INET; 221464562Sgshapiro goto v4retry; 221564562Sgshapiro } 221664562Sgshapiro if (v6found) 221764562Sgshapiro goto v6tempfail; 221890792Sgshapiro#endif /* NETINET6 */ 221964562Sgshapiro save_errno = errno; 222038032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 222164562Sgshapiro errno = save_errno; 222264562Sgshapiro return EX_NOHOST; 222338032Speter } 222438032Speter addr.sa.sa_family = hp->h_addrtype; 222538032Speter switch (hp->h_addrtype) 222638032Speter { 222790792Sgshapiro#if NETINET 222838032Speter case AF_INET: 222964562Sgshapiro memmove(&addr.sin.sin_addr, 223064562Sgshapiro hp->h_addr, 223138032Speter INADDRSZ); 223238032Speter break; 223390792Sgshapiro#endif /* NETINET */ 223438032Speter 223590792Sgshapiro#if NETINET6 223664562Sgshapiro case AF_INET6: 223764562Sgshapiro memmove(&addr.sin6.sin6_addr, 223864562Sgshapiro hp->h_addr, 223964562Sgshapiro IN6ADDRSZ); 224064562Sgshapiro break; 224190792Sgshapiro#endif /* NETINET6 */ 224264562Sgshapiro 224338032Speter default: 224438032Speter if (hp->h_length > sizeof addr.sa.sa_data) 224538032Speter { 224638032Speter syserr("makeconnection: long sa_data: family %d len %d", 224738032Speter hp->h_addrtype, hp->h_length); 224838032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 224964562Sgshapiro errno = EINVAL; 225038032Speter return EX_NOHOST; 225138032Speter } 225290792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 225338032Speter break; 225438032Speter } 225538032Speter addrno = 1; 225638032Speter } 225738032Speter 225838032Speter /* 225938032Speter ** Determine the port number. 226038032Speter */ 226138032Speter 226238032Speter if (port == 0) 226338032Speter { 226490792Sgshapiro#ifdef NO_GETSERVBYNAME 226564562Sgshapiro port = htons(25); 226690792Sgshapiro#else /* NO_GETSERVBYNAME */ 226738032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 226838032Speter 226938032Speter if (sp == NULL) 227038032Speter { 227138032Speter if (LogLevel > 2) 227238032Speter sm_syslog(LOG_ERR, NOQID, 227364562Sgshapiro "makeconnection: service \"smtp\" unknown"); 227438032Speter port = htons(25); 227538032Speter } 227638032Speter else 227738032Speter port = sp->s_port; 227890792Sgshapiro#endif /* NO_GETSERVBYNAME */ 227938032Speter } 228038032Speter 228190792Sgshapiro#if NETINET6 228290792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 228390792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 228490792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 228590792Sgshapiro { 228690792Sgshapiro /* 228790792Sgshapiro ** Ignore mapped IPv4 address since 228890792Sgshapiro ** there is a ClientPortOptions setting 228990792Sgshapiro ** for IPv4. 229090792Sgshapiro */ 229190792Sgshapiro 229290792Sgshapiro goto nextaddr; 229390792Sgshapiro } 229490792Sgshapiro#endif /* NETINET6 */ 229590792Sgshapiro 229638032Speter switch (addr.sa.sa_family) 229738032Speter { 229890792Sgshapiro#if NETINET 229938032Speter case AF_INET: 230038032Speter addr.sin.sin_port = port; 230138032Speter addrlen = sizeof (struct sockaddr_in); 230238032Speter break; 230390792Sgshapiro#endif /* NETINET */ 230438032Speter 230590792Sgshapiro#if NETINET6 230664562Sgshapiro case AF_INET6: 230764562Sgshapiro addr.sin6.sin6_port = port; 230864562Sgshapiro addrlen = sizeof (struct sockaddr_in6); 230964562Sgshapiro break; 231090792Sgshapiro#endif /* NETINET6 */ 231164562Sgshapiro 231290792Sgshapiro#if NETISO 231338032Speter case AF_ISO: 231438032Speter /* assume two byte transport selector */ 231564562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 231638032Speter addrlen = sizeof (struct sockaddr_iso); 231738032Speter break; 231890792Sgshapiro#endif /* NETISO */ 231938032Speter 232038032Speter default: 232138032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 232238032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 232364562Sgshapiro errno = EINVAL; 232490792Sgshapiro#if NETINET6 232571345Sgshapiro if (hp != NULL) 232671345Sgshapiro freehostent(hp); 232790792Sgshapiro#endif /* NETINET6 */ 232864562Sgshapiro return EX_NOHOST; 232938032Speter } 233038032Speter 233138032Speter /* 233238032Speter ** Try to actually open the connection. 233338032Speter */ 233438032Speter 233590792Sgshapiro#if XLA 233638032Speter /* if too many connections, don't bother trying */ 233738032Speter if (!xla_noqueue_ok(host)) 233871345Sgshapiro { 233990792Sgshapiro# if NETINET6 234071345Sgshapiro if (hp != NULL) 234171345Sgshapiro freehostent(hp); 234290792Sgshapiro# endif /* NETINET6 */ 234338032Speter return EX_TEMPFAIL; 234471345Sgshapiro } 234590792Sgshapiro#endif /* XLA */ 234638032Speter 234790792Sgshapiro firstconnect = true; 234838032Speter for (;;) 234938032Speter { 235038032Speter if (tTd(16, 1)) 235190792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 235290792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 235390792Sgshapiro (int) addr.sa.sa_family); 235438032Speter 235538032Speter /* save for logging */ 235638032Speter CurHostAddr = addr; 235738032Speter 235890792Sgshapiro#if HASRRESVPORT 235938032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 236038032Speter { 236138032Speter int rport = IPPORT_RESERVED - 1; 236238032Speter 236338032Speter s = rresvport(&rport); 236438032Speter } 236538032Speter else 236690792Sgshapiro#endif /* HASRRESVPORT */ 236738032Speter { 236890792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 236938032Speter } 237038032Speter if (s < 0) 237138032Speter { 237264562Sgshapiro save_errno = errno; 237338032Speter syserr("makeconnection: cannot create socket"); 237490792Sgshapiro#if XLA 237538032Speter xla_host_end(host); 237690792Sgshapiro#endif /* XLA */ 237738032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 237890792Sgshapiro#if NETINET6 237971345Sgshapiro if (hp != NULL) 238071345Sgshapiro freehostent(hp); 238190792Sgshapiro#endif /* NETINET6 */ 238264562Sgshapiro errno = save_errno; 238338032Speter return EX_TEMPFAIL; 238438032Speter } 238538032Speter 238690792Sgshapiro#ifdef SO_SNDBUF 238790792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 238838032Speter { 238938032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 239090792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 239190792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 239238032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 239338032Speter } 239490792Sgshapiro#endif /* SO_SNDBUF */ 239590792Sgshapiro#ifdef SO_RCVBUF 239690792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 239764562Sgshapiro { 239864562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 239990792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 240090792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 240164562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 240264562Sgshapiro } 240390792Sgshapiro#endif /* SO_RCVBUF */ 240438032Speter 240538032Speter if (tTd(16, 1)) 240690792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 240738032Speter 240838032Speter /* turn on network debugging? */ 240938032Speter if (tTd(16, 101)) 241038032Speter { 241138032Speter int on = 1; 241264562Sgshapiro 241338032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 241438032Speter (char *)&on, sizeof on); 241538032Speter } 241690792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 241790792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 241890792Sgshapiro errno = 0; /* for debugging */ 241938032Speter 242064562Sgshapiro if (clt_bind) 242164562Sgshapiro { 242264562Sgshapiro int on = 1; 242364562Sgshapiro 242464562Sgshapiro switch (clt_addr.sa.sa_family) 242564562Sgshapiro { 242690792Sgshapiro#if NETINET 242764562Sgshapiro case AF_INET: 242864562Sgshapiro if (clt_addr.sin.sin_port != 0) 242964562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 243064562Sgshapiro SO_REUSEADDR, 243164562Sgshapiro (char *) &on, 243264562Sgshapiro sizeof on); 243364562Sgshapiro break; 243490792Sgshapiro#endif /* NETINET */ 243564562Sgshapiro 243690792Sgshapiro#if NETINET6 243764562Sgshapiro case AF_INET6: 243864562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 243964562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 244064562Sgshapiro SO_REUSEADDR, 244164562Sgshapiro (char *) &on, 244264562Sgshapiro sizeof on); 244364562Sgshapiro break; 244490792Sgshapiro#endif /* NETINET6 */ 244564562Sgshapiro } 244664562Sgshapiro 244764562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 244864562Sgshapiro { 244964562Sgshapiro save_errno = errno; 245064562Sgshapiro (void) close(s); 245164562Sgshapiro errno = save_errno; 245264562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 245364562Sgshapiro anynet_ntoa(&clt_addr)); 245490792Sgshapiro#if NETINET6 245571345Sgshapiro if (hp != NULL) 245671345Sgshapiro freehostent(hp); 245790792Sgshapiro#endif /* NETINET6 */ 245864562Sgshapiro errno = save_errno; 245964562Sgshapiro return EX_TEMPFAIL; 246064562Sgshapiro } 246164562Sgshapiro } 246264562Sgshapiro 246338032Speter /* 246438032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 246538032Speter ** Time out the connect to avoid this problem. 246638032Speter */ 246738032Speter 246838032Speter if (setjmp(CtxConnectTimeout) == 0) 246938032Speter { 247038032Speter int i; 247138032Speter 247238032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 247390792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 247490792Sgshapiro connecttimeout, 0); 247538032Speter else if (TimeOuts.to_connect != 0) 247690792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 247790792Sgshapiro connecttimeout, 0); 247838032Speter else 247938032Speter ev = NULL; 248038032Speter 248164562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 248264562Sgshapiro { 248390792Sgshapiro#if NETINET 248464562Sgshapiro case AF_INET: 248564562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 248664562Sgshapiro break; 248790792Sgshapiro#endif /* NETINET */ 248864562Sgshapiro 248990792Sgshapiro#if NETINET6 249064562Sgshapiro case AF_INET6: 249164562Sgshapiro memmove(&addr.sin6.sin6_addr, 249264562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 249364562Sgshapiro IN6ADDRSZ); 249464562Sgshapiro break; 249590792Sgshapiro#endif /* NETINET6 */ 249664562Sgshapiro } 249738032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 249864562Sgshapiro save_errno = errno; 249938032Speter if (ev != NULL) 250090792Sgshapiro sm_clrevent(ev); 250138032Speter if (i >= 0) 250238032Speter break; 250338032Speter } 250438032Speter else 250564562Sgshapiro save_errno = errno; 250638032Speter 250738032Speter /* if running demand-dialed connection, try again */ 250890792Sgshapiro if (DialDelay > 0 && firstconnect && 250990792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 251038032Speter { 251138032Speter if (tTd(16, 1)) 251290792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 251390792Sgshapiro sm_errstring(save_errno)); 251490792Sgshapiro firstconnect = false; 251564562Sgshapiro (void) sleep(DialDelay); 251638032Speter continue; 251738032Speter } 251838032Speter 251938032Speter /* couldn't connect.... figure out why */ 252038032Speter (void) close(s); 252138032Speter 252290792Sgshapiro if (LogLevel > 13) 252338032Speter sm_syslog(LOG_INFO, e->e_id, 252438032Speter "makeconnection (%s [%s]) failed: %s", 252538032Speter host, anynet_ntoa(&addr), 252690792Sgshapiro sm_errstring(save_errno)); 252738032Speter 252890792Sgshapiro#if NETINET6 252990792Sgshapironextaddr: 253090792Sgshapiro#endif /* NETINET6 */ 253190792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 253290792Sgshapiro (enough == 0 || curtime() < enough)) 253338032Speter { 253438032Speter if (tTd(16, 1)) 253590792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 253690792Sgshapiro sm_errstring(save_errno)); 253738032Speter switch (addr.sa.sa_family) 253838032Speter { 253990792Sgshapiro#if NETINET 254038032Speter case AF_INET: 254164562Sgshapiro memmove(&addr.sin.sin_addr, 254264562Sgshapiro hp->h_addr_list[addrno++], 254364562Sgshapiro INADDRSZ); 254438032Speter break; 254590792Sgshapiro#endif /* NETINET */ 254638032Speter 254790792Sgshapiro#if NETINET6 254864562Sgshapiro case AF_INET6: 254964562Sgshapiro memmove(&addr.sin6.sin6_addr, 255064562Sgshapiro hp->h_addr_list[addrno++], 255164562Sgshapiro IN6ADDRSZ); 255264562Sgshapiro break; 255390792Sgshapiro#endif /* NETINET6 */ 255464562Sgshapiro 255538032Speter default: 255664562Sgshapiro memmove(addr.sa.sa_data, 255764562Sgshapiro hp->h_addr_list[addrno++], 255838032Speter hp->h_length); 255938032Speter break; 256038032Speter } 256138032Speter continue; 256238032Speter } 256364562Sgshapiro errno = save_errno; 256438032Speter 256590792Sgshapiro#if NETINET6 256664562Sgshapiro if (family == AF_INET6) 256764562Sgshapiro { 256864562Sgshapiro if (tTd(16, 1)) 256990792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 257090792Sgshapiro sm_errstring(save_errno)); 257190792Sgshapiro v6found = true; 257264562Sgshapiro family = AF_INET; 257371345Sgshapiro if (hp != NULL) 257471345Sgshapiro { 257571345Sgshapiro freehostent(hp); 257671345Sgshapiro hp = NULL; 257771345Sgshapiro } 257864562Sgshapiro goto v4retry; 257964562Sgshapiro } 258064562Sgshapiro v6tempfail: 258190792Sgshapiro#endif /* NETINET6 */ 258238032Speter /* couldn't open connection */ 258390792Sgshapiro#if NETINET6 258464562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 258564562Sgshapiro if (errno > 0) 258690792Sgshapiro#endif /* NETINET6 */ 258764562Sgshapiro save_errno = errno; 258864562Sgshapiro if (tTd(16, 1)) 258990792Sgshapiro sm_dprintf("Connect failed (%s)\n", 259090792Sgshapiro sm_errstring(save_errno)); 259190792Sgshapiro#if XLA 259238032Speter xla_host_end(host); 259390792Sgshapiro#endif /* XLA */ 259438032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 259590792Sgshapiro#if NETINET6 259671345Sgshapiro if (hp != NULL) 259771345Sgshapiro freehostent(hp); 259890792Sgshapiro#endif /* NETINET6 */ 259964562Sgshapiro errno = save_errno; 260038032Speter return EX_TEMPFAIL; 260138032Speter } 260238032Speter 260390792Sgshapiro#if NETINET6 260471345Sgshapiro if (hp != NULL) 260571345Sgshapiro { 260671345Sgshapiro freehostent(hp); 260771345Sgshapiro hp = NULL; 260871345Sgshapiro } 260990792Sgshapiro#endif /* NETINET6 */ 261071345Sgshapiro 261138032Speter /* connection ok, put it into canonical form */ 261264562Sgshapiro mci->mci_out = NULL; 261390792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 261490792Sgshapiro (void *) &s, 261590792Sgshapiro SM_IO_WRONLY, NULL)) == NULL || 261638032Speter (s = dup(s)) < 0 || 261790792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 261890792Sgshapiro (void *) &s, 261990792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 262038032Speter { 262164562Sgshapiro save_errno = errno; 262238032Speter syserr("cannot open SMTP client channel, fd=%d", s); 262338032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 262464562Sgshapiro if (mci->mci_out != NULL) 262590792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 262664562Sgshapiro (void) close(s); 262764562Sgshapiro errno = save_errno; 262838032Speter return EX_TEMPFAIL; 262938032Speter } 263090792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 263138032Speter 263290792Sgshapiro /* set {client_flags} */ 263390792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 263490792Sgshapiro { 263590792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 263690792Sgshapiro macid("{client_flags}"), 263790792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 263890792Sgshapiro } 263990792Sgshapiro else 264090792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 264190792Sgshapiro macid("{client_flags}"), ""); 264290792Sgshapiro 264390792Sgshapiro /* "add" {client_flags} to bitmap */ 264490792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 264590792Sgshapiro { 264690792Sgshapiro /* look for just this one flag */ 264790792Sgshapiro setbitn(D_IFNHELO, d_flags); 264890792Sgshapiro } 264990792Sgshapiro 265064562Sgshapiro /* find out name for Interface through which we connect */ 265164562Sgshapiro len = sizeof addr; 265264562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 265364562Sgshapiro { 265464562Sgshapiro char *name; 265590792Sgshapiro char family[5]; 265664562Sgshapiro 265790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 265890792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 265990792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 266090792Sgshapiro addr.sa.sa_family); 266190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 266290792Sgshapiro macid("{if_family_out}"), family); 266364562Sgshapiro 266464562Sgshapiro name = hostnamebyanyaddr(&addr); 266590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 266690792Sgshapiro macid("{if_name_out}"), name); 266764562Sgshapiro if (LogLevel > 11) 266864562Sgshapiro { 266964562Sgshapiro /* log connection information */ 267064562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 267164562Sgshapiro "SMTP outgoing connect on %.40s", name); 267264562Sgshapiro } 267364562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 267464562Sgshapiro { 267564562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 267664562Sgshapiro mci->mci_heloname = newstr(name); 267764562Sgshapiro } 267864562Sgshapiro } 267964562Sgshapiro else 268064562Sgshapiro { 268190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 268290792Sgshapiro macid("{if_name_out}"), NULL); 268390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 268490792Sgshapiro macid("{if_addr_out}"), NULL); 268590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 268690792Sgshapiro macid("{if_family_out}"), NULL); 268764562Sgshapiro } 268838032Speter mci_setstat(mci, EX_OK, NULL, NULL); 268964562Sgshapiro return EX_OK; 269038032Speter} 269164562Sgshapiro 269264562Sgshapirostatic void 269364562Sgshapiroconnecttimeout() 269464562Sgshapiro{ 269577349Sgshapiro /* 269677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 269777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 269877349Sgshapiro ** DOING. 269977349Sgshapiro */ 270077349Sgshapiro 270164562Sgshapiro errno = ETIMEDOUT; 270264562Sgshapiro longjmp(CtxConnectTimeout, 1); 270364562Sgshapiro} 270490792Sgshapiro/* 270564562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 270664562Sgshapiro** 270764562Sgshapiro** Parameters: 270864562Sgshapiro** mux_path -- the path of the socket to connect to. 270964562Sgshapiro** mci -- a pointer to the mail connection information 271064562Sgshapiro** structure to be filled in. 271164562Sgshapiro** 271264562Sgshapiro** Returns: 271364562Sgshapiro** An exit code telling whether the connection could be 271464562Sgshapiro** made and if not why not. 271564562Sgshapiro** 271664562Sgshapiro** Side Effects: 271764562Sgshapiro** none. 271864562Sgshapiro*/ 271964562Sgshapiro 272090792Sgshapiro#if NETUNIX 272190792Sgshapiroint 272290792Sgshapiromakeconnection_ds(mux_path, mci) 272364562Sgshapiro char *mux_path; 272464562Sgshapiro register MCI *mci; 272564562Sgshapiro{ 272664562Sgshapiro int sock; 272764562Sgshapiro int rval, save_errno; 272864562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 272964562Sgshapiro struct sockaddr_un unix_addr; 273064562Sgshapiro 273164562Sgshapiro /* if not safe, don't connect */ 273264562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 273364562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 273464562Sgshapiro 273564562Sgshapiro if (rval != 0) 273664562Sgshapiro { 273764562Sgshapiro syserr("makeconnection_ds: unsafe domain socket"); 273864562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 273964562Sgshapiro errno = rval; 274064562Sgshapiro return EX_TEMPFAIL; 274164562Sgshapiro } 274264562Sgshapiro 274364562Sgshapiro /* prepare address structure */ 274464562Sgshapiro memset(&unix_addr, '\0', sizeof unix_addr); 274564562Sgshapiro unix_addr.sun_family = AF_UNIX; 274664562Sgshapiro 274764562Sgshapiro if (strlen(mux_path) >= sizeof unix_addr.sun_path) 274864562Sgshapiro { 274964562Sgshapiro syserr("makeconnection_ds: domain socket name too long"); 275090792Sgshapiro 275190792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 275264562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 275364562Sgshapiro errno = ENAMETOOLONG; 275464562Sgshapiro return EX_UNAVAILABLE; 275564562Sgshapiro } 275690792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 275790792Sgshapiro sizeof unix_addr.sun_path); 275864562Sgshapiro 275964562Sgshapiro /* initialize domain socket */ 276064562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 276164562Sgshapiro if (sock == -1) 276264562Sgshapiro { 276364562Sgshapiro save_errno = errno; 276464562Sgshapiro syserr("makeconnection_ds: could not create domain socket"); 276564562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 276664562Sgshapiro errno = save_errno; 276764562Sgshapiro return EX_TEMPFAIL; 276864562Sgshapiro } 276964562Sgshapiro 277064562Sgshapiro /* connect to server */ 277164562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 277264562Sgshapiro sizeof(unix_addr)) == -1) 277364562Sgshapiro { 277464562Sgshapiro save_errno = errno; 277564562Sgshapiro syserr("Could not connect to socket %s", mux_path); 277664562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 277764562Sgshapiro (void) close(sock); 277864562Sgshapiro errno = save_errno; 277964562Sgshapiro return EX_TEMPFAIL; 278064562Sgshapiro } 278164562Sgshapiro 278264562Sgshapiro /* connection ok, put it into canonical form */ 278364562Sgshapiro mci->mci_out = NULL; 278490792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 278590792Sgshapiro (void *) &sock, SM_IO_WRONLY, NULL)) 278690792Sgshapiro == NULL 278790792Sgshapiro || (sock = dup(sock)) < 0 || 278890792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 278990792Sgshapiro (void *) &sock, SM_IO_RDONLY, NULL)) 279090792Sgshapiro == NULL) 279164562Sgshapiro { 279264562Sgshapiro save_errno = errno; 279364562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 279464562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 279564562Sgshapiro if (mci->mci_out != NULL) 279690792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 279764562Sgshapiro (void) close(sock); 279864562Sgshapiro errno = save_errno; 279964562Sgshapiro return EX_TEMPFAIL; 280064562Sgshapiro } 280190792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 280264562Sgshapiro 280364562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 280464562Sgshapiro errno = 0; 280564562Sgshapiro return EX_OK; 280664562Sgshapiro} 280790792Sgshapiro#endif /* NETUNIX */ 280890792Sgshapiro/* 280990792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 281077349Sgshapiro** 281177349Sgshapiro** Parameters: 281290792Sgshapiro** none. 281377349Sgshapiro** 281477349Sgshapiro** Returns: 281577349Sgshapiro** none. 281677349Sgshapiro** 281777349Sgshapiro** Side Effects: 281890792Sgshapiro** closes control socket, exits. 281977349Sgshapiro*/ 282077349Sgshapiro 282190792Sgshapirovoid 282290792Sgshapiroshutdown_daemon() 282377349Sgshapiro{ 282490792Sgshapiro int i; 282590792Sgshapiro char *reason; 282677349Sgshapiro 282790792Sgshapiro sm_allsignals(true); 282890792Sgshapiro 282990792Sgshapiro reason = ShutdownRequest; 283090792Sgshapiro ShutdownRequest = NULL; 283190792Sgshapiro PendingSignal = 0; 283290792Sgshapiro 283390792Sgshapiro if (LogLevel > 79) 283490792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)", 283590792Sgshapiro reason == NULL ? "implicit call" : reason); 283690792Sgshapiro 283790792Sgshapiro FileName = NULL; 283890792Sgshapiro closecontrolsocket(true); 283990792Sgshapiro#if XLA 284090792Sgshapiro xla_all_end(); 284190792Sgshapiro#endif /* XLA */ 284290792Sgshapiro 284390792Sgshapiro for (i = 0; i < NDaemons; i++) 284490792Sgshapiro { 284590792Sgshapiro if (Daemons[i].d_socket >= 0) 284690792Sgshapiro { 284790792Sgshapiro (void) close(Daemons[i].d_socket); 284890792Sgshapiro Daemons[i].d_socket = -1; 284990792Sgshapiro 285090792Sgshapiro#if _FFR_DAEMON_NETUNIX 285190792Sgshapiro# if NETUNIX 285290792Sgshapiro /* Remove named sockets */ 285390792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 285490792Sgshapiro { 285590792Sgshapiro int rval; 285690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 285790792Sgshapiro 285890792Sgshapiro /* if not safe, don't use it */ 285990792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 286090792Sgshapiro RunAsUid, RunAsGid, 286190792Sgshapiro RunAsUserName, sff, 286290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 286390792Sgshapiro if (rval == 0 && 286490792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 286590792Sgshapiro { 286690792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 286790792Sgshapiro "Could not remove daemon %s socket: %s: %s", 286890792Sgshapiro Daemons[i].d_name, 286990792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 287090792Sgshapiro sm_errstring(errno)); 287190792Sgshapiro } 287290792Sgshapiro } 287390792Sgshapiro# endif /* NETUNIX */ 287490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 287590792Sgshapiro } 287690792Sgshapiro } 287790792Sgshapiro 287890792Sgshapiro finis(false, true, EX_OK); 287977349Sgshapiro} 288090792Sgshapiro/* 288177349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 288277349Sgshapiro** 288377349Sgshapiro** Parameters: 288477349Sgshapiro** none. 288577349Sgshapiro** 288677349Sgshapiro** Returns: 288777349Sgshapiro** none. 288877349Sgshapiro** 288977349Sgshapiro** Side Effects: 289077349Sgshapiro** restarts the daemon or exits if restart fails. 289177349Sgshapiro*/ 289277349Sgshapiro 289380785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 289480785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 289580785Sgshapirodo \ 289680785Sgshapiro{ \ 289790792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 289880785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 289990792Sgshapiro (void) sm_signal((sig), (old)); \ 290080785Sgshapiro} while (0) 290180785Sgshapiro 290290792Sgshapirovoid 290377349Sgshapirorestart_daemon() 290477349Sgshapiro{ 290590792Sgshapiro bool drop; 290677349Sgshapiro int i; 290777349Sgshapiro int save_errno; 290877349Sgshapiro char *reason; 290980785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 291077349Sgshapiro extern int DtableSize; 291177349Sgshapiro 291280785Sgshapiro /* clear the events to turn off SIGALRMs */ 291390792Sgshapiro sm_clear_events(); 291490792Sgshapiro sm_allsignals(true); 291577349Sgshapiro 291677349Sgshapiro reason = RestartRequest; 291777349Sgshapiro RestartRequest = NULL; 291877349Sgshapiro PendingSignal = 0; 291977349Sgshapiro 292077349Sgshapiro if (SaveArgv[0][0] != '/') 292177349Sgshapiro { 292277349Sgshapiro if (LogLevel > 3) 292377349Sgshapiro sm_syslog(LOG_INFO, NOQID, 292477349Sgshapiro "could not restart: need full path"); 292590792Sgshapiro finis(false, true, EX_OSFILE); 292690792Sgshapiro /* NOTREACHED */ 292777349Sgshapiro } 292877349Sgshapiro if (LogLevel > 3) 292977349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 293077349Sgshapiro SaveArgv[0], 293177349Sgshapiro reason == NULL ? "implicit call" : reason); 293277349Sgshapiro 293390792Sgshapiro closecontrolsocket(true); 293490792Sgshapiro 293590792Sgshapiro /* 293690792Sgshapiro ** Want to drop to the user who started the process in all cases 293790792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 293890792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 293990792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 294090792Sgshapiro */ 294190792Sgshapiro 294290792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 294390792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 294490792Sgshapiro 294590792Sgshapiro if (drop_privileges(drop) != EX_OK) 294677349Sgshapiro { 294777349Sgshapiro if (LogLevel > 0) 294877349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 294990792Sgshapiro "could not drop privileges: %s", 295090792Sgshapiro sm_errstring(errno)); 295190792Sgshapiro finis(false, true, EX_OSERR); 295290792Sgshapiro /* NOTREACHED */ 295377349Sgshapiro } 295477349Sgshapiro 295577349Sgshapiro /* arrange for all the files to be closed */ 295677349Sgshapiro for (i = 3; i < DtableSize; i++) 295777349Sgshapiro { 295877349Sgshapiro register int j; 295977349Sgshapiro 296077349Sgshapiro if ((j = fcntl(i, F_GETFD, 0)) != -1) 296177349Sgshapiro (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); 296277349Sgshapiro } 296390792Sgshapiro#if SM_CONF_SHM 296490792Sgshapiro cleanup_shm(DaemonPid == getpid()); 296590792Sgshapiro#endif /* SM_CONF_SHM */ 296677349Sgshapiro 296780785Sgshapiro /* 296880785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 296980785Sgshapiro ** However, the default action can be "terminate", so it isn't 297080785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 297180785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 297280785Sgshapiro */ 297380785Sgshapiro 297480785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 297580785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 297680785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 297780785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 297880785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 297980785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 298080785Sgshapiro#ifdef SIGUSR1 298180785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 298280785Sgshapiro#endif /* SIGUSR1 */ 298390792Sgshapiro sm_allsignals(false); 298477349Sgshapiro 298577349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 298677349Sgshapiro save_errno = errno; 298777349Sgshapiro 298880785Sgshapiro /* block signals again and restore needed signals */ 298990792Sgshapiro sm_allsignals(true); 299080785Sgshapiro 299180785Sgshapiro /* For finis() events */ 299290792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 299380785Sgshapiro 299480785Sgshapiro#ifdef SIGUSR1 299580785Sgshapiro /* For debugging finis() */ 299690792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 299780785Sgshapiro#endif /* SIGUSR1 */ 299877349Sgshapiro 299977349Sgshapiro errno = save_errno; 300077349Sgshapiro if (LogLevel > 0) 300190792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 300290792Sgshapiro SaveArgv[0], sm_errstring(errno)); 300390792Sgshapiro finis(false, true, EX_OSFILE); 300490792Sgshapiro /* NOTREACHED */ 300577349Sgshapiro} 300690792Sgshapiro/* 300738032Speter** MYHOSTNAME -- return the name of this host. 300838032Speter** 300938032Speter** Parameters: 301038032Speter** hostbuf -- a place to return the name of this host. 301138032Speter** size -- the size of hostbuf. 301238032Speter** 301338032Speter** Returns: 301438032Speter** A list of aliases for this host. 301538032Speter** 301638032Speter** Side Effects: 301738032Speter** Adds numeric codes to $=w. 301838032Speter*/ 301938032Speter 302038032Speterstruct hostent * 302138032Spetermyhostname(hostbuf, size) 302238032Speter char hostbuf[]; 302338032Speter int size; 302438032Speter{ 302538032Speter register struct hostent *hp; 302638032Speter 302773188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 302890792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 302964562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 303090792Sgshapiro#if NETINET && NETINET6 303180785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 303280785Sgshapiro { 303380785Sgshapiro /* 303480785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 303580785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 303680785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 303780785Sgshapiro */ 303880785Sgshapiro 303980785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 304080785Sgshapiro } 304190792Sgshapiro#endif /* NETINET && NETINET6 */ 304238032Speter if (hp == NULL) 304338032Speter return NULL; 304438032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 304564562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 304664562Sgshapiro 304790792Sgshapiro#if NETINFO 304864562Sgshapiro if (strchr(hostbuf, '.') == NULL) 304938032Speter { 305064562Sgshapiro char *domainname; 305164562Sgshapiro 305264562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 305364562Sgshapiro "domain", '\0'); 305464562Sgshapiro if (domainname != NULL && 305564562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 305690792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 305738032Speter } 305890792Sgshapiro#endif /* NETINFO */ 305938032Speter 306038032Speter /* 306138032Speter ** If there is still no dot in the name, try looking for a 306238032Speter ** dotted alias. 306338032Speter */ 306438032Speter 306538032Speter if (strchr(hostbuf, '.') == NULL) 306638032Speter { 306738032Speter char **ha; 306838032Speter 306964562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 307038032Speter { 307138032Speter if (strchr(*ha, '.') != NULL) 307238032Speter { 307364562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 307438032Speter hostbuf[size - 1] = '\0'; 307538032Speter break; 307638032Speter } 307738032Speter } 307838032Speter } 307938032Speter 308038032Speter /* 308138032Speter ** If _still_ no dot, wait for a while and try again -- it is 308238032Speter ** possible that some service is starting up. This can result 308338032Speter ** in excessive delays if the system is badly configured, but 308438032Speter ** there really isn't a way around that, particularly given that 308538032Speter ** the config file hasn't been read at this point. 308638032Speter ** All in all, a bit of a mess. 308738032Speter */ 308838032Speter 308938032Speter if (strchr(hostbuf, '.') == NULL && 309090792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 309138032Speter { 309238032Speter sm_syslog(LOG_CRIT, NOQID, 309364562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 309464562Sgshapiro hostbuf); 309538032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 309638032Speter hostbuf); 309764562Sgshapiro (void) sleep(60); 309890792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 309938032Speter { 310038032Speter sm_syslog(LOG_ALERT, NOQID, 310164562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 310264562Sgshapiro hostbuf); 310338032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 310438032Speter hostbuf); 310538032Speter } 310638032Speter } 310764562Sgshapiro return hp; 310838032Speter} 310990792Sgshapiro/* 311038032Speter** ADDRCMP -- compare two host addresses 311138032Speter** 311238032Speter** Parameters: 311338032Speter** hp -- hostent structure for the first address 311438032Speter** ha -- actual first address 311538032Speter** sa -- second address 311638032Speter** 311738032Speter** Returns: 311838032Speter** 0 -- if ha and sa match 311938032Speter** else -- they don't match 312038032Speter*/ 312138032Speter 312264562Sgshapirostatic int 312338032Speteraddrcmp(hp, ha, sa) 312438032Speter struct hostent *hp; 312538032Speter char *ha; 312638032Speter SOCKADDR *sa; 312738032Speter{ 312890792Sgshapiro#if NETINET6 312990792Sgshapiro unsigned char *a; 313090792Sgshapiro#endif /* NETINET6 */ 313164562Sgshapiro 313238032Speter switch (sa->sa.sa_family) 313338032Speter { 313490792Sgshapiro#if NETINET 313538032Speter case AF_INET: 313638032Speter if (hp->h_addrtype == AF_INET) 313764562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 313838032Speter break; 313990792Sgshapiro#endif /* NETINET */ 314038032Speter 314190792Sgshapiro#if NETINET6 314264562Sgshapiro case AF_INET6: 314390792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 314464562Sgshapiro 314564562Sgshapiro /* Straight binary comparison */ 314664562Sgshapiro if (hp->h_addrtype == AF_INET6) 314764562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 314864562Sgshapiro 314964562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 315064562Sgshapiro if (hp->h_addrtype == AF_INET && 315164562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 315264562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 315364562Sgshapiro break; 315490792Sgshapiro#endif /* NETINET6 */ 315538032Speter } 315638032Speter return -1; 315738032Speter} 315890792Sgshapiro/* 315964562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 316038032Speter** 316138032Speter** Uses RFC1413 protocol to try to get info from the other end. 316238032Speter** 316338032Speter** Parameters: 316438032Speter** fd -- the descriptor 316590792Sgshapiro** may_be_forged -- an outage that is set to true if the 316638032Speter** forward lookup of RealHostName does not match 316790792Sgshapiro** RealHostAddr; set to false if they do match. 316838032Speter** 316938032Speter** Returns: 317038032Speter** The user@host information associated with this descriptor. 317138032Speter*/ 317238032Speter 317338032Speterstatic jmp_buf CtxAuthTimeout; 317438032Speter 317538032Speterstatic void 317638032Speterauthtimeout() 317738032Speter{ 317877349Sgshapiro /* 317977349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 318077349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 318177349Sgshapiro ** DOING. 318277349Sgshapiro */ 318377349Sgshapiro 318477349Sgshapiro errno = ETIMEDOUT; 318538032Speter longjmp(CtxAuthTimeout, 1); 318638032Speter} 318738032Speter 318838032Speterchar * 318938032Spetergetauthinfo(fd, may_be_forged) 319038032Speter int fd; 319138032Speter bool *may_be_forged; 319238032Speter{ 319390792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 319438032Speter SOCKADDR_LEN_T falen; 319538032Speter register char *volatile p = NULL; 319638032Speter SOCKADDR la; 319738032Speter SOCKADDR_LEN_T lalen; 319890792Sgshapiro#ifndef NO_GETSERVBYNAME 319938032Speter register struct servent *sp; 320090792Sgshapiro# if NETINET 320190792Sgshapiro static unsigned short port4 = 0; 320290792Sgshapiro# endif /* NETINET */ 320390792Sgshapiro# if NETINET6 320490792Sgshapiro static unsigned short port6 = 0; 320590792Sgshapiro# endif /* NETINET6 */ 320690792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 320738032Speter volatile int s; 320838032Speter int i = 0; 320990792Sgshapiro size_t len; 321090792Sgshapiro SM_EVENT *ev; 321138032Speter int nleft; 321238032Speter struct hostent *hp; 321338032Speter char *ostype = NULL; 321438032Speter char **ha; 321538032Speter char ibuf[MAXNAME + 1]; 321638032Speter static char hbuf[MAXNAME * 2 + 11]; 321738032Speter 321890792Sgshapiro *may_be_forged = false; 321938032Speter falen = sizeof RealHostAddr; 322038032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 322138032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 322238032Speter { 322364562Sgshapiro if (i < 0) 322464562Sgshapiro { 322564562Sgshapiro /* 322664562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 322764562Sgshapiro ** errno in this case, so a mis-report doesn't 322864562Sgshapiro ** happen later. 322964562Sgshapiro */ 323090792Sgshapiro 323164562Sgshapiro if (errno != ENOTSOCK) 323264562Sgshapiro return NULL; 323364562Sgshapiro errno = 0; 323464562Sgshapiro } 323590792Sgshapiro (void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName, 323690792Sgshapiro "@localhost"); 323738032Speter if (tTd(9, 1)) 323890792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 323938032Speter return hbuf; 324038032Speter } 324138032Speter 324238032Speter if (RealHostName == NULL) 324338032Speter { 324438032Speter /* translate that to a host name */ 324538032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 324638032Speter if (strlen(RealHostName) > MAXNAME) 324790792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 324838032Speter } 324938032Speter 325038032Speter /* cross check RealHostName with forward DNS lookup */ 325190792Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] != '[' && 325290792Sgshapiro RealHostName[0] != '[') 325338032Speter { 325480785Sgshapiro int family; 325580785Sgshapiro 325680785Sgshapiro family = RealHostAddr.sa.sa_family; 325790792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 325880785Sgshapiro /* 325980785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 326080785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 326180785Sgshapiro ** address(es) for addrcmp() to compare against 326280785Sgshapiro ** RealHostAddr. 326380785Sgshapiro ** 326480785Sgshapiro ** Actually, we only need to do this for systems 326580785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 326680785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 326780785Sgshapiro ** flag. A better fix to this problem is to add this 326880785Sgshapiro ** functionality to our stub getipnodebyname(). 326980785Sgshapiro */ 327080785Sgshapiro 327180785Sgshapiro if (family == AF_INET6 && 327280785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 327380785Sgshapiro family = AF_INET; 327490792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 327580785Sgshapiro 327638032Speter /* try to match the reverse against the forward lookup */ 327780785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 327838032Speter if (hp == NULL) 327990792Sgshapiro *may_be_forged = true; 328038032Speter else 328138032Speter { 328238032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 328390792Sgshapiro { 328438032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 328538032Speter break; 328690792Sgshapiro } 328738032Speter *may_be_forged = *ha == NULL; 328890792Sgshapiro#if NETINET6 328971345Sgshapiro freehostent(hp); 329071345Sgshapiro hp = NULL; 329190792Sgshapiro#endif /* NETINET6 */ 329238032Speter } 329338032Speter } 329438032Speter 329538032Speter if (TimeOuts.to_ident == 0) 329638032Speter goto noident; 329738032Speter 329838032Speter lalen = sizeof la; 329964562Sgshapiro switch (RealHostAddr.sa.sa_family) 330038032Speter { 330190792Sgshapiro#if NETINET 330264562Sgshapiro case AF_INET: 330364562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 330464562Sgshapiro lalen <= 0 || 330564562Sgshapiro la.sa.sa_family != AF_INET) 330664562Sgshapiro { 330764562Sgshapiro /* no ident info */ 330864562Sgshapiro goto noident; 330964562Sgshapiro } 331064562Sgshapiro port = RealHostAddr.sin.sin_port; 331138032Speter 331264562Sgshapiro /* create ident query */ 331390792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 331464562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 331564562Sgshapiro ntohs(la.sin.sin_port)); 331638032Speter 331764562Sgshapiro /* create local address */ 331864562Sgshapiro la.sin.sin_port = 0; 331938032Speter 332064562Sgshapiro /* create foreign address */ 332190792Sgshapiro# ifdef NO_GETSERVBYNAME 332238032Speter RealHostAddr.sin.sin_port = htons(113); 332390792Sgshapiro# else /* NO_GETSERVBYNAME */ 332490792Sgshapiro 332590792Sgshapiro /* 332690792Sgshapiro ** getservbyname() consumes about 5% of the time 332790792Sgshapiro ** when receiving a small message (almost all of the time 332890792Sgshapiro ** spent in this routine). 332990792Sgshapiro ** Hence we store the port in a static variable 333090792Sgshapiro ** to save this time. 333190792Sgshapiro ** The portnumber shouldn't change very often... 333290792Sgshapiro ** This code makes the assumption that the port number 333390792Sgshapiro ** is not 0. 333490792Sgshapiro */ 333590792Sgshapiro 333690792Sgshapiro if (port4 == 0) 333790792Sgshapiro { 333890792Sgshapiro sp = getservbyname("auth", "tcp"); 333990792Sgshapiro if (sp != NULL) 334090792Sgshapiro port4 = sp->s_port; 334190792Sgshapiro else 334290792Sgshapiro port4 = htons(113); 334390792Sgshapiro } 334490792Sgshapiro RealHostAddr.sin.sin_port = port4; 334564562Sgshapiro break; 334690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 334790792Sgshapiro#endif /* NETINET */ 334838032Speter 334990792Sgshapiro#if NETINET6 335064562Sgshapiro case AF_INET6: 335164562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 335264562Sgshapiro lalen <= 0 || 335364562Sgshapiro la.sa.sa_family != AF_INET6) 335464562Sgshapiro { 335564562Sgshapiro /* no ident info */ 335664562Sgshapiro goto noident; 335764562Sgshapiro } 335864562Sgshapiro port = RealHostAddr.sin6.sin6_port; 335964562Sgshapiro 336064562Sgshapiro /* create ident query */ 336190792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 336264562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 336364562Sgshapiro ntohs(la.sin6.sin6_port)); 336464562Sgshapiro 336564562Sgshapiro /* create local address */ 336664562Sgshapiro la.sin6.sin6_port = 0; 336764562Sgshapiro 336864562Sgshapiro /* create foreign address */ 336990792Sgshapiro# ifdef NO_GETSERVBYNAME 337064562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 337190792Sgshapiro# else /* NO_GETSERVBYNAME */ 337290792Sgshapiro if (port6 == 0) 337390792Sgshapiro { 337490792Sgshapiro sp = getservbyname("auth", "tcp"); 337590792Sgshapiro if (sp != NULL) 337690792Sgshapiro port6 = sp->s_port; 337790792Sgshapiro else 337890792Sgshapiro port6 = htons(113); 337990792Sgshapiro } 338090792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 338164562Sgshapiro break; 338290792Sgshapiro# endif /* NO_GETSERVBYNAME */ 338390792Sgshapiro#endif /* NETINET6 */ 338464562Sgshapiro default: 338564562Sgshapiro /* no ident info */ 338664562Sgshapiro goto noident; 338764562Sgshapiro } 338864562Sgshapiro 338938032Speter s = -1; 339038032Speter if (setjmp(CtxAuthTimeout) != 0) 339138032Speter { 339238032Speter if (s >= 0) 339338032Speter (void) close(s); 339438032Speter goto noident; 339538032Speter } 339638032Speter 339738032Speter /* put a timeout around the whole thing */ 339890792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 339938032Speter 340064562Sgshapiro 340138032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 340264562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 340338032Speter if (s < 0) 340438032Speter { 340590792Sgshapiro sm_clrevent(ev); 340638032Speter goto noident; 340738032Speter } 340864562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 340964562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 341038032Speter goto closeident; 341138032Speter 341238032Speter if (tTd(9, 10)) 341390792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 341438032Speter 341538032Speter /* send query */ 341638032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 341738032Speter goto closeident; 341838032Speter 341938032Speter /* get result */ 342038032Speter p = &ibuf[0]; 342138032Speter nleft = sizeof ibuf - 1; 342238032Speter while ((i = read(s, p, nleft)) > 0) 342338032Speter { 342438032Speter p += i; 342538032Speter nleft -= i; 342638032Speter *p = '\0'; 342790792Sgshapiro if (strchr(ibuf, '\n') != NULL || nleft <= 0) 342838032Speter break; 342938032Speter } 343038032Speter (void) close(s); 343190792Sgshapiro sm_clrevent(ev); 343238032Speter if (i < 0 || p == &ibuf[0]) 343338032Speter goto noident; 343438032Speter 343538032Speter if (*--p == '\n' && *--p == '\r') 343638032Speter p--; 343738032Speter *++p = '\0'; 343838032Speter 343938032Speter if (tTd(9, 3)) 344090792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 344138032Speter 344238032Speter /* parse result */ 344338032Speter p = strchr(ibuf, ':'); 344438032Speter if (p == NULL) 344538032Speter { 344638032Speter /* malformed response */ 344738032Speter goto noident; 344838032Speter } 344938032Speter while (isascii(*++p) && isspace(*p)) 345038032Speter continue; 345190792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 345238032Speter { 345338032Speter /* presumably an error string */ 345438032Speter goto noident; 345538032Speter } 345638032Speter p += 6; 345738032Speter while (isascii(*p) && isspace(*p)) 345838032Speter p++; 345938032Speter if (*p++ != ':') 346038032Speter { 346138032Speter /* either useridxx or malformed response */ 346238032Speter goto noident; 346338032Speter } 346438032Speter 346538032Speter /* p now points to the OSTYPE field */ 346638032Speter while (isascii(*p) && isspace(*p)) 346738032Speter p++; 346838032Speter ostype = p; 346938032Speter p = strchr(p, ':'); 347038032Speter if (p == NULL) 347138032Speter { 347238032Speter /* malformed response */ 347338032Speter goto noident; 347438032Speter } 347538032Speter else 347638032Speter { 347738032Speter char *charset; 347838032Speter 347938032Speter *p = '\0'; 348038032Speter charset = strchr(ostype, ','); 348138032Speter if (charset != NULL) 348238032Speter *charset = '\0'; 348338032Speter } 348438032Speter 348538032Speter /* 1413 says don't do this -- but it's broken otherwise */ 348638032Speter while (isascii(*++p) && isspace(*p)) 348738032Speter continue; 348838032Speter 348938032Speter /* p now points to the authenticated name -- copy carefully */ 349090792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 349138032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 349238032Speter { 349390792Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf); 349438032Speter cleanstrcpy(&hbuf[6], p, MAXNAME); 349538032Speter } 349638032Speter else 349738032Speter cleanstrcpy(hbuf, p, MAXNAME); 349890792Sgshapiro len = strlen(hbuf); 349990792Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@", 350090792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 350138032Speter goto postident; 350238032Speter 350338032Spetercloseident: 350438032Speter (void) close(s); 350590792Sgshapiro sm_clrevent(ev); 350638032Speter 350738032Speternoident: 350864562Sgshapiro /* put back the original incoming port */ 350964562Sgshapiro switch (RealHostAddr.sa.sa_family) 351064562Sgshapiro { 351190792Sgshapiro#if NETINET 351264562Sgshapiro case AF_INET: 351364562Sgshapiro if (port > 0) 351464562Sgshapiro RealHostAddr.sin.sin_port = port; 351564562Sgshapiro break; 351690792Sgshapiro#endif /* NETINET */ 351764562Sgshapiro 351890792Sgshapiro#if NETINET6 351964562Sgshapiro case AF_INET6: 352064562Sgshapiro if (port > 0) 352164562Sgshapiro RealHostAddr.sin6.sin6_port = port; 352264562Sgshapiro break; 352390792Sgshapiro#endif /* NETINET6 */ 352464562Sgshapiro } 352564562Sgshapiro 352638032Speter if (RealHostName == NULL) 352738032Speter { 352838032Speter if (tTd(9, 1)) 352990792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 353038032Speter return NULL; 353138032Speter } 353290792Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf); 353338032Speter 353438032Speterpostident: 353590792Sgshapiro#if IP_SRCROUTE 353690792Sgshapiro# ifndef GET_IPOPT_DST 353790792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 353890792Sgshapiro# endif /* ! GET_IPOPT_DST */ 353938032Speter /* 354038032Speter ** Extract IP source routing information. 354138032Speter ** 354238032Speter ** Format of output for a connection from site a through b 354338032Speter ** through c to d: 354438032Speter ** loose: @site-c@site-b:site-a 354538032Speter ** strict: !@site-c@site-b:site-a 354638032Speter ** 354738032Speter ** o - pointer within ipopt_list structure. 354838032Speter ** q - pointer within ls/ss rr route data 354938032Speter ** p - pointer to hbuf 355038032Speter */ 355138032Speter 355238032Speter if (RealHostAddr.sa.sa_family == AF_INET) 355338032Speter { 355438032Speter SOCKOPT_LEN_T ipoptlen; 355538032Speter int j; 355690792Sgshapiro unsigned char *q; 355790792Sgshapiro unsigned char *o; 355838032Speter int l; 355964562Sgshapiro struct IPOPTION ipopt; 356038032Speter 356138032Speter ipoptlen = sizeof ipopt; 356238032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 356338032Speter (char *) &ipopt, &ipoptlen) < 0) 356438032Speter goto noipsr; 356538032Speter if (ipoptlen == 0) 356638032Speter goto noipsr; 356790792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 356890792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 356938032Speter { 357038032Speter switch (*o) 357138032Speter { 357264562Sgshapiro case IPOPT_EOL: 357338032Speter o = NULL; 357438032Speter break; 357538032Speter 357638032Speter case IPOPT_NOP: 357738032Speter o++; 357838032Speter break; 357938032Speter 358038032Speter case IPOPT_SSRR: 358138032Speter case IPOPT_LSRR: 358238032Speter /* 358338032Speter ** Source routing. 358438032Speter ** o[0] is the option type (loose/strict). 358538032Speter ** o[1] is the length of this option, 358638032Speter ** including option type and 358738032Speter ** length. 358838032Speter ** o[2] is the pointer into the route 358938032Speter ** data. 359038032Speter ** o[3] begins the route data. 359138032Speter */ 359238032Speter 359338032Speter p = &hbuf[strlen(hbuf)]; 359438032Speter l = sizeof hbuf - (hbuf - p) - 6; 359590792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 359690792Sgshapiro " [%s@%.*s", 359790792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 359890792Sgshapiro l > 240 ? 120 : l / 2, 359990792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 360038032Speter i = strlen(p); 360138032Speter p += i; 360238032Speter l -= strlen(p); 360338032Speter 360438032Speter j = o[1] / sizeof(struct in_addr) - 1; 360538032Speter 360638032Speter /* q skips length and router pointer to data */ 360738032Speter q = &o[3]; 360838032Speter for ( ; j >= 0; j--) 360938032Speter { 361064562Sgshapiro struct in_addr addr; 361164562Sgshapiro 361238032Speter memcpy(&addr, q, sizeof(addr)); 361390792Sgshapiro (void) sm_snprintf(p, 361490792Sgshapiro SPACELEFT(hbuf, p), 361590792Sgshapiro "%c%.*s", 361690792Sgshapiro j != 0 ? '@' : ':', 361790792Sgshapiro l > 240 ? 120 : 361890792Sgshapiro j == 0 ? l : l / 2, 361990792Sgshapiro inet_ntoa(addr)); 362038032Speter i = strlen(p); 362138032Speter p += i; 362238032Speter l -= i + 1; 362364562Sgshapiro q += sizeof(struct in_addr); 362438032Speter } 362538032Speter o += o[1]; 362638032Speter break; 362738032Speter 362838032Speter default: 362938032Speter /* Skip over option */ 363038032Speter o += o[1]; 363138032Speter break; 363238032Speter } 363338032Speter } 363490792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 363538032Speter goto postipsr; 363638032Speter } 363738032Speter 363838032Speternoipsr: 363990792Sgshapiro#endif /* IP_SRCROUTE */ 364038032Speter if (RealHostName != NULL && RealHostName[0] != '[') 364138032Speter { 364238032Speter p = &hbuf[strlen(hbuf)]; 364390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 364490792Sgshapiro anynet_ntoa(&RealHostAddr)); 364538032Speter } 364638032Speter if (*may_be_forged) 364738032Speter { 364838032Speter p = &hbuf[strlen(hbuf)]; 364990792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 365090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 365190792Sgshapiro macid("{client_resolve}"), "FORGED"); 365238032Speter } 365338032Speter 365490792Sgshapiro#if IP_SRCROUTE 365538032Speterpostipsr: 365690792Sgshapiro#endif /* IP_SRCROUTE */ 365764562Sgshapiro 365864562Sgshapiro /* put back the original incoming port */ 365964562Sgshapiro switch (RealHostAddr.sa.sa_family) 366064562Sgshapiro { 366190792Sgshapiro#if NETINET 366264562Sgshapiro case AF_INET: 366364562Sgshapiro if (port > 0) 366464562Sgshapiro RealHostAddr.sin.sin_port = port; 366564562Sgshapiro break; 366690792Sgshapiro#endif /* NETINET */ 366764562Sgshapiro 366890792Sgshapiro#if NETINET6 366964562Sgshapiro case AF_INET6: 367064562Sgshapiro if (port > 0) 367164562Sgshapiro RealHostAddr.sin6.sin6_port = port; 367264562Sgshapiro break; 367390792Sgshapiro#endif /* NETINET6 */ 367464562Sgshapiro } 367564562Sgshapiro 367690792Sgshapiro if (tTd(9, 1)) 367790792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 367838032Speter return hbuf; 367938032Speter} 368090792Sgshapiro/* 368138032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 368238032Speter** 368338032Speter** Parameters: 368438032Speter** map -- a pointer to this map. 368538032Speter** name -- the (presumably unqualified) hostname. 368638032Speter** av -- unused -- for compatibility with other mapping 368738032Speter** functions. 368838032Speter** statp -- an exit status (out parameter) -- set to 368938032Speter** EX_TEMPFAIL if the name server is unavailable. 369038032Speter** 369138032Speter** Returns: 369238032Speter** The mapping, if found. 369338032Speter** NULL if no mapping found. 369438032Speter** 369538032Speter** Side Effects: 369638032Speter** Looks up the host specified in hbuf. If it is not 369738032Speter** the canonical name for that host, return the canonical 369838032Speter** name (unless MF_MATCHONLY is set, which will cause the 369938032Speter** status only to be returned). 370038032Speter*/ 370138032Speter 370238032Speterchar * 370338032Speterhost_map_lookup(map, name, av, statp) 370438032Speter MAP *map; 370538032Speter char *name; 370638032Speter char **av; 370738032Speter int *statp; 370838032Speter{ 370938032Speter register struct hostent *hp; 371090792Sgshapiro#if NETINET 371138032Speter struct in_addr in_addr; 371290792Sgshapiro#endif /* NETINET */ 371390792Sgshapiro#if NETINET6 371464562Sgshapiro struct in6_addr in6_addr; 371590792Sgshapiro#endif /* NETINET6 */ 371664562Sgshapiro char *cp, *ans = NULL; 371738032Speter register STAB *s; 371890792Sgshapiro time_t now; 371990792Sgshapiro#if NAMED_BIND 372090792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 372190792Sgshapiro int SM_NONVOLATILE retry = 0; 372290792Sgshapiro#endif /* NAMED_BIND */ 372338032Speter char hbuf[MAXNAME + 1]; 372438032Speter 372538032Speter /* 372638032Speter ** See if we have already looked up this name. If so, just 372790792Sgshapiro ** return it (unless expired). 372838032Speter */ 372938032Speter 373090792Sgshapiro now = curtime(); 373138032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 373290792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 373390792Sgshapiro s->s_namecanon.nc_exp >= now) 373438032Speter { 373538032Speter if (tTd(9, 1)) 373690792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 373790792Sgshapiro name, 373890792Sgshapiro s->s_namecanon.nc_cname == NULL 373938032Speter ? "NULL" 374038032Speter : s->s_namecanon.nc_cname); 374138032Speter errno = s->s_namecanon.nc_errno; 374273188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 374338032Speter *statp = s->s_namecanon.nc_stat; 374438032Speter if (*statp == EX_TEMPFAIL) 374538032Speter { 374638032Speter CurEnv->e_status = "4.4.3"; 374738032Speter message("851 %s: Name server timeout", 374838032Speter shortenstring(name, 33)); 374938032Speter } 375038032Speter if (*statp != EX_OK) 375138032Speter return NULL; 375238032Speter if (s->s_namecanon.nc_cname == NULL) 375338032Speter { 375438032Speter syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", 375564562Sgshapiro name, 375664562Sgshapiro s->s_namecanon.nc_errno, 375764562Sgshapiro s->s_namecanon.nc_herrno); 375838032Speter return NULL; 375938032Speter } 376038032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 376138032Speter cp = map_rewrite(map, name, strlen(name), NULL); 376238032Speter else 376338032Speter cp = map_rewrite(map, 376438032Speter s->s_namecanon.nc_cname, 376538032Speter strlen(s->s_namecanon.nc_cname), 376638032Speter av); 376738032Speter return cp; 376838032Speter } 376938032Speter 377038032Speter /* 377138032Speter ** If we are running without a regular network connection (usually 377238032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 377338032Speter ** lookups because those could try to connect to a server. 377438032Speter */ 377538032Speter 377664562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 377764562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 377838032Speter { 377938032Speter if (tTd(9, 1)) 378090792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 378138032Speter *statp = EX_TEMPFAIL; 378238032Speter return NULL; 378338032Speter } 378438032Speter 378538032Speter /* 378638032Speter ** If first character is a bracket, then it is an address 378738032Speter ** lookup. Address is copied into a temporary buffer to 378838032Speter ** strip the brackets and to preserve name if address is 378938032Speter ** unknown. 379038032Speter */ 379138032Speter 379264562Sgshapiro if (tTd(9, 1)) 379390792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 379490792Sgshapiro#if NAMED_BIND 379590792Sgshapiro if (map->map_timeout > 0) 379690792Sgshapiro { 379790792Sgshapiro retrans = _res.retrans; 379890792Sgshapiro _res.retrans = map->map_timeout; 379990792Sgshapiro } 380090792Sgshapiro if (map->map_retry > 0) 380190792Sgshapiro { 380290792Sgshapiro retry = _res.retry; 380390792Sgshapiro _res.retry = map->map_retry; 380490792Sgshapiro } 380590792Sgshapiro#endif /* NAMED_BIND */ 380690792Sgshapiro 380790792Sgshapiro /* set default TTL */ 380890792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 380938032Speter if (*name != '[') 381038032Speter { 381190792Sgshapiro int ttl; 381290792Sgshapiro 381390792Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof hbuf); 381490792Sgshapiro if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl)) 381590792Sgshapiro { 381664562Sgshapiro ans = hbuf; 381790792Sgshapiro if (ttl > 0) 381890792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 381990792Sgshapiro SM_DEFAULT_TTL); 382090792Sgshapiro } 382164562Sgshapiro } 382264562Sgshapiro else 382364562Sgshapiro { 382464562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 382571345Sgshapiro { 382671345Sgshapiro if (tTd(9, 1)) 382790792Sgshapiro sm_dprintf("FAILED\n"); 382864562Sgshapiro return NULL; 382971345Sgshapiro } 383064562Sgshapiro *cp = '\0'; 383164562Sgshapiro 383264562Sgshapiro hp = NULL; 383390792Sgshapiro#if NETINET 383464562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 383564562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 383664562Sgshapiro INADDRSZ, AF_INET); 383790792Sgshapiro#endif /* NETINET */ 383890792Sgshapiro#if NETINET6 383964562Sgshapiro if (hp == NULL && 384090792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 384164562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 384264562Sgshapiro IN6ADDRSZ, AF_INET6); 384390792Sgshapiro#endif /* NETINET6 */ 384464562Sgshapiro *cp = ']'; 384564562Sgshapiro 384664562Sgshapiro if (hp != NULL) 384738032Speter { 384864562Sgshapiro /* found a match -- copy out */ 384990792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 385090792Sgshapiro#if NETINET6 385190792Sgshapiro if (ans == hp->h_name) 385290792Sgshapiro { 385390792Sgshapiro static char n[MAXNAME + 1]; 385490792Sgshapiro 385590792Sgshapiro /* hp->h_name is about to disappear */ 385690792Sgshapiro (void) sm_strlcpy(n, ans, sizeof n); 385790792Sgshapiro ans = n; 385890792Sgshapiro } 385971345Sgshapiro freehostent(hp); 386071345Sgshapiro hp = NULL; 386190792Sgshapiro#endif /* NETINET6 */ 386238032Speter } 386364562Sgshapiro } 386490792Sgshapiro#if NAMED_BIND 386590792Sgshapiro if (map->map_timeout > 0) 386690792Sgshapiro _res.retrans = retrans; 386790792Sgshapiro if (map->map_retry > 0) 386890792Sgshapiro _res.retry = retry; 386990792Sgshapiro#endif /* NAMED_BIND */ 387038032Speter 387164562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 387238032Speter 387364562Sgshapiro /* Found an answer */ 387464562Sgshapiro if (ans != NULL) 387564562Sgshapiro { 387664562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 387790792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 387890792Sgshapiro sm_free(s->s_namecanon.nc_cname); 387990792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 388064562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 388164562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 388264562Sgshapiro else 388364562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 388471345Sgshapiro if (tTd(9, 1)) 388590792Sgshapiro sm_dprintf("FOUND %s\n", ans); 388664562Sgshapiro return cp; 388738032Speter } 388838032Speter 388964562Sgshapiro 389064562Sgshapiro /* No match found */ 389138032Speter s->s_namecanon.nc_errno = errno; 389290792Sgshapiro#if NAMED_BIND 389338032Speter s->s_namecanon.nc_herrno = h_errno; 389464562Sgshapiro if (tTd(9, 1)) 389590792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 389664562Sgshapiro switch (h_errno) 389738032Speter { 389864562Sgshapiro case TRY_AGAIN: 389964562Sgshapiro if (UseNameServer) 390064562Sgshapiro { 390164562Sgshapiro CurEnv->e_status = "4.4.3"; 390264562Sgshapiro message("851 %s: Name server timeout", 390364562Sgshapiro shortenstring(name, 33)); 390464562Sgshapiro } 390564562Sgshapiro *statp = EX_TEMPFAIL; 390664562Sgshapiro break; 390764562Sgshapiro 390864562Sgshapiro case HOST_NOT_FOUND: 390964562Sgshapiro case NO_DATA: 391064562Sgshapiro *statp = EX_NOHOST; 391164562Sgshapiro break; 391264562Sgshapiro 391364562Sgshapiro case NO_RECOVERY: 391464562Sgshapiro *statp = EX_SOFTWARE; 391564562Sgshapiro break; 391664562Sgshapiro 391764562Sgshapiro default: 391864562Sgshapiro *statp = EX_UNAVAILABLE; 391964562Sgshapiro break; 392038032Speter } 392190792Sgshapiro#else /* NAMED_BIND */ 392264562Sgshapiro if (tTd(9, 1)) 392390792Sgshapiro sm_dprintf("FAIL\n"); 392464562Sgshapiro *statp = EX_NOHOST; 392590792Sgshapiro#endif /* NAMED_BIND */ 392664562Sgshapiro s->s_namecanon.nc_stat = *statp; 392764562Sgshapiro return NULL; 392838032Speter} 392938032Speter/* 393090792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 393138032Speter** 393238032Speter** Parameters: 393390792Sgshapiro** map -- a pointer to this map. 393490792Sgshapiro** args -- argument string. 393538032Speter** 393638032Speter** Returns: 393790792Sgshapiro** true. 393838032Speter*/ 393938032Speter 394038032Speterbool 394138032Speterhost_map_init(map, args) 394238032Speter MAP *map; 394338032Speter char *args; 394438032Speter{ 394538032Speter register char *p = args; 394638032Speter 394738032Speter for (;;) 394838032Speter { 394938032Speter while (isascii(*p) && isspace(*p)) 395038032Speter p++; 395138032Speter if (*p != '-') 395238032Speter break; 395338032Speter switch (*++p) 395438032Speter { 395538032Speter case 'a': 395638032Speter map->map_app = ++p; 395738032Speter break; 395838032Speter 395938032Speter case 'T': 396038032Speter map->map_tapp = ++p; 396138032Speter break; 396238032Speter 396338032Speter case 'm': 396438032Speter map->map_mflags |= MF_MATCHONLY; 396538032Speter break; 396638032Speter 396738032Speter case 't': 396838032Speter map->map_mflags |= MF_NODEFER; 396938032Speter break; 397064562Sgshapiro 397164562Sgshapiro case 'S': /* only for consistency */ 397264562Sgshapiro map->map_spacesub = *++p; 397364562Sgshapiro break; 397464562Sgshapiro 397564562Sgshapiro case 'D': 397664562Sgshapiro map->map_mflags |= MF_DEFER; 397764562Sgshapiro break; 397890792Sgshapiro 397990792Sgshapiro case 'd': 398090792Sgshapiro { 398190792Sgshapiro char *h; 398290792Sgshapiro 398390792Sgshapiro while (isascii(*++p) && isspace(*p)) 398490792Sgshapiro continue; 398590792Sgshapiro h = strchr(p, ' '); 398690792Sgshapiro if (h != NULL) 398790792Sgshapiro *h = '\0'; 398890792Sgshapiro map->map_timeout = convtime(p, 's'); 398990792Sgshapiro if (h != NULL) 399090792Sgshapiro *h = ' '; 399190792Sgshapiro } 399290792Sgshapiro break; 399390792Sgshapiro 399490792Sgshapiro case 'r': 399590792Sgshapiro while (isascii(*++p) && isspace(*p)) 399690792Sgshapiro continue; 399790792Sgshapiro map->map_retry = atoi(p); 399890792Sgshapiro break; 399938032Speter } 400038032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 400138032Speter p++; 400238032Speter if (*p != '\0') 400338032Speter *p++ = '\0'; 400438032Speter } 400538032Speter if (map->map_app != NULL) 400638032Speter map->map_app = newstr(map->map_app); 400738032Speter if (map->map_tapp != NULL) 400838032Speter map->map_tapp = newstr(map->map_tapp); 400990792Sgshapiro return true; 401038032Speter} 401190792Sgshapiro 401264562Sgshapiro#if NETINET6 401364562Sgshapiro/* 401464562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 401564562Sgshapiro** 401664562Sgshapiro** Parameters: 401764562Sgshapiro** s6a -- a pointer to an in6_addr structure. 401864562Sgshapiro** dst -- buffer to store result in 401964562Sgshapiro** dst_len -- size of dst buffer 402064562Sgshapiro** 402164562Sgshapiro** Returns: 402264562Sgshapiro** A printable version of that structure. 402364562Sgshapiro*/ 402490792Sgshapiro 402564562Sgshapirochar * 402664562Sgshapiroanynet_ntop(s6a, dst, dst_len) 402764562Sgshapiro struct in6_addr *s6a; 402864562Sgshapiro char *dst; 402964562Sgshapiro size_t dst_len; 403064562Sgshapiro{ 403164562Sgshapiro register char *ap; 403264562Sgshapiro 403364562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 403464562Sgshapiro ap = (char *) inet_ntop(AF_INET, 403564562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 403664562Sgshapiro dst, dst_len); 403764562Sgshapiro else 403890792Sgshapiro { 403990792Sgshapiro char *d; 404090792Sgshapiro size_t sz; 404190792Sgshapiro 404290792Sgshapiro /* Save pointer to beginning of string */ 404390792Sgshapiro d = dst; 404490792Sgshapiro 404590792Sgshapiro /* Add IPv6: protocol tag */ 404690792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 404790792Sgshapiro if (sz >= dst_len) 404890792Sgshapiro return NULL; 404990792Sgshapiro dst += sz; 405090792Sgshapiro dst_len -= sz; 405164562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 405290792Sgshapiro 405390792Sgshapiro /* Restore pointer to beginning of string */ 405490792Sgshapiro if (ap != NULL) 405590792Sgshapiro ap = d; 405690792Sgshapiro } 405764562Sgshapiro return ap; 405864562Sgshapiro} 405990792Sgshapiro 406090792Sgshapiro/* 406190792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 406290792Sgshapiro** 406390792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 406490792Sgshapiro** 406590792Sgshapiro** Parameters: 406690792Sgshapiro** family -- address family 406790792Sgshapiro** src -- string 406890792Sgshapiro** dst -- destination address structure 406990792Sgshapiro** 407090792Sgshapiro** Returns: 407190792Sgshapiro** 1 if the address was valid 407290792Sgshapiro** 0 if the address wasn't parseable 407390792Sgshapiro** -1 if error 407490792Sgshapiro*/ 407590792Sgshapiro 407690792Sgshapiroint 407790792Sgshapiroanynet_pton(family, src, dst) 407890792Sgshapiro int family; 407990792Sgshapiro const char *src; 408090792Sgshapiro void *dst; 408190792Sgshapiro{ 408290792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 408390792Sgshapiro src += 5; 408490792Sgshapiro return inet_pton(family, src, dst); 408590792Sgshapiro} 408664562Sgshapiro#endif /* NETINET6 */ 408790792Sgshapiro/* 408838032Speter** ANYNET_NTOA -- convert a network address to printable form. 408938032Speter** 409038032Speter** Parameters: 409138032Speter** sap -- a pointer to a sockaddr structure. 409238032Speter** 409338032Speter** Returns: 409438032Speter** A printable version of that sockaddr. 409538032Speter*/ 409638032Speter 409738032Speter#ifdef USE_SOCK_STREAM 409838032Speter 409964562Sgshapiro# if NETLINK 410064562Sgshapiro# include <net/if_dl.h> 410164562Sgshapiro# endif /* NETLINK */ 410238032Speter 410338032Speterchar * 410438032Speteranynet_ntoa(sap) 410538032Speter register SOCKADDR *sap; 410638032Speter{ 410738032Speter register char *bp; 410838032Speter register char *ap; 410938032Speter int l; 411038032Speter static char buf[100]; 411138032Speter 411238032Speter /* check for null/zero family */ 411338032Speter if (sap == NULL) 411438032Speter return "NULLADDR"; 411538032Speter if (sap->sa.sa_family == 0) 411638032Speter return "0"; 411738032Speter 411838032Speter switch (sap->sa.sa_family) 411938032Speter { 412064562Sgshapiro# if NETUNIX 412138032Speter case AF_UNIX: 412264562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 412390792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]", 412490792Sgshapiro sap->sunix.sun_path); 412564562Sgshapiro else 412690792Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf); 412738032Speter return buf; 412864562Sgshapiro# endif /* NETUNIX */ 412938032Speter 413064562Sgshapiro# if NETINET 413138032Speter case AF_INET: 413264562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 413364562Sgshapiro# endif /* NETINET */ 413438032Speter 413564562Sgshapiro# if NETINET6 413664562Sgshapiro case AF_INET6: 413764562Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf); 413864562Sgshapiro if (ap != NULL) 413964562Sgshapiro return ap; 414064562Sgshapiro break; 414164562Sgshapiro# endif /* NETINET6 */ 414264562Sgshapiro 414364562Sgshapiro# if NETLINK 414438032Speter case AF_LINK: 414590792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[LINK: %s]", 414690792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 414738032Speter return buf; 414864562Sgshapiro# endif /* NETLINK */ 414938032Speter default: 415038032Speter /* this case is needed when nothing is #defined */ 415138032Speter /* in order to keep the switch syntactically correct */ 415238032Speter break; 415338032Speter } 415438032Speter 415538032Speter /* unknown family -- just dump bytes */ 415690792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 415738032Speter bp = &buf[strlen(buf)]; 415838032Speter ap = sap->sa.sa_data; 415938032Speter for (l = sizeof sap->sa.sa_data; --l >= 0; ) 416038032Speter { 416190792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 416290792Sgshapiro *ap++ & 0377); 416338032Speter bp += 3; 416438032Speter } 416538032Speter *--bp = '\0'; 416638032Speter return buf; 416738032Speter} 416890792Sgshapiro/* 416938032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 417038032Speter** 417138032Speter** Parameters: 417238032Speter** sap -- SOCKADDR pointer 417338032Speter** 417438032Speter** Returns: 417538032Speter** text representation of host name. 417638032Speter** 417738032Speter** Side Effects: 417838032Speter** none. 417938032Speter*/ 418038032Speter 418138032Speterchar * 418238032Speterhostnamebyanyaddr(sap) 418338032Speter register SOCKADDR *sap; 418438032Speter{ 418538032Speter register struct hostent *hp; 418664562Sgshapiro# if NAMED_BIND 418738032Speter int saveretry; 418864562Sgshapiro# endif /* NAMED_BIND */ 418964562Sgshapiro# if NETINET6 419064562Sgshapiro struct in6_addr in6_addr; 419164562Sgshapiro# endif /* NETINET6 */ 419238032Speter 419364562Sgshapiro# if NAMED_BIND 419438032Speter /* shorten name server timeout to avoid higher level timeouts */ 419538032Speter saveretry = _res.retry; 419664562Sgshapiro if (_res.retry * _res.retrans > 20) 419764562Sgshapiro _res.retry = 20 / _res.retrans; 419864562Sgshapiro# endif /* NAMED_BIND */ 419938032Speter 420038032Speter switch (sap->sa.sa_family) 420138032Speter { 420264562Sgshapiro# if NETINET 420338032Speter case AF_INET: 420438032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 420590792Sgshapiro INADDRSZ, AF_INET); 420638032Speter break; 420764562Sgshapiro# endif /* NETINET */ 420838032Speter 420964562Sgshapiro# if NETINET6 421064562Sgshapiro case AF_INET6: 421164562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 421290792Sgshapiro IN6ADDRSZ, AF_INET6); 421364562Sgshapiro break; 421464562Sgshapiro# endif /* NETINET6 */ 421564562Sgshapiro 421664562Sgshapiro# if NETISO 421738032Speter case AF_ISO: 421838032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 421990792Sgshapiro sizeof sap->siso.siso_addr, AF_ISO); 422038032Speter break; 422164562Sgshapiro# endif /* NETISO */ 422238032Speter 422364562Sgshapiro# if NETUNIX 422438032Speter case AF_UNIX: 422538032Speter hp = NULL; 422638032Speter break; 422764562Sgshapiro# endif /* NETUNIX */ 422838032Speter 422938032Speter default: 423090792Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data, 423190792Sgshapiro sap->sa.sa_family); 423238032Speter break; 423338032Speter } 423438032Speter 423564562Sgshapiro# if NAMED_BIND 423638032Speter _res.retry = saveretry; 423764562Sgshapiro# endif /* NAMED_BIND */ 423838032Speter 423964562Sgshapiro# if NETINET || NETINET6 424064562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 424164562Sgshapiro# if NETINET6 424264562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 424364562Sgshapiro# endif /* NETINET6 */ 424464562Sgshapiro# if NETINET 424564562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 424664562Sgshapiro# endif /* NETINET */ 424764562Sgshapiro ) 424871345Sgshapiro { 424971345Sgshapiro char *name; 425071345Sgshapiro 425190792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 425290792Sgshapiro# if NETINET6 425371345Sgshapiro if (name == hp->h_name) 425471345Sgshapiro { 425571345Sgshapiro static char n[MAXNAME + 1]; 425671345Sgshapiro 425771345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 425890792Sgshapiro (void) sm_strlcpy(n, name, sizeof n); 425971345Sgshapiro name = n; 426071345Sgshapiro } 426171345Sgshapiro freehostent(hp); 426290792Sgshapiro# endif /* NETINET6 */ 426371345Sgshapiro return name; 426471345Sgshapiro } 426564562Sgshapiro# endif /* NETINET || NETINET6 */ 426671345Sgshapiro 426790792Sgshapiro# if NETINET6 426871345Sgshapiro if (hp != NULL) 426971345Sgshapiro { 427071345Sgshapiro freehostent(hp); 427171345Sgshapiro hp = NULL; 427271345Sgshapiro } 427390792Sgshapiro# endif /* NETINET6 */ 427471345Sgshapiro 427564562Sgshapiro# if NETUNIX 427664562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 427738032Speter return "localhost"; 427864562Sgshapiro# endif /* NETUNIX */ 427938032Speter { 428038032Speter static char buf[203]; 428138032Speter 428290792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[%.200s]", 428390792Sgshapiro anynet_ntoa(sap)); 428438032Speter return buf; 428538032Speter } 428638032Speter} 428764562Sgshapiro#endif /* USE_SOCK_STREAM */ 4288