daemon.c revision 98121
138032Speter/* 294334Sgshapiro * Copyright (c) 1998-2002 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 1698121SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.612 2002/05/02 19:40:52 ca Exp $") 1764562Sgshapiro 1838032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 1938032Speter# define USE_SOCK_STREAM 1 2064562Sgshapiro#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */ 2138032Speter 2290792Sgshapiro#if defined(USE_SOCK_STREAM) 2364562Sgshapiro# if NETINET || NETINET6 2464562Sgshapiro# include <arpa/inet.h> 2564562Sgshapiro# endif /* NETINET || NETINET6 */ 2638032Speter# if NAMED_BIND 2738032Speter# ifndef NO_DATA 2838032Speter# define NO_DATA NO_ADDRESS 2964562Sgshapiro# endif /* ! NO_DATA */ 3064562Sgshapiro# endif /* NAMED_BIND */ 3190792Sgshapiro#endif /* defined(USE_SOCK_STREAM) */ 3238032Speter 3390792Sgshapiro#if STARTTLS 3490792Sgshapiro# include <openssl/rand.h> 3590792Sgshapiro#endif /* STARTTLS */ 3638032Speter 3790792Sgshapiro#include <sys/time.h> 3866494Sgshapiro 3990792Sgshapiro#if IP_SRCROUTE && NETINET 4090792Sgshapiro# include <netinet/in_systm.h> 4190792Sgshapiro# include <netinet/ip.h> 4290792Sgshapiro# if HAS_IN_H 4390792Sgshapiro# include <netinet/in.h> 4490792Sgshapiro# ifndef IPOPTION 4590792Sgshapiro# define IPOPTION ip_opts 4690792Sgshapiro# define IP_LIST ip_opts 4790792Sgshapiro# define IP_DST ip_dst 4890792Sgshapiro# endif /* ! IPOPTION */ 4990792Sgshapiro# else /* HAS_IN_H */ 5090792Sgshapiro# include <netinet/ip_var.h> 5190792Sgshapiro# ifndef IPOPTION 5290792Sgshapiro# define IPOPTION ipoption 5390792Sgshapiro# define IP_LIST ipopt_list 5490792Sgshapiro# define IP_DST ipopt_dst 5590792Sgshapiro# endif /* ! IPOPTION */ 5690792Sgshapiro# endif /* HAS_IN_H */ 5790792Sgshapiro#endif /* IP_SRCROUTE && NETINET */ 5838032Speter 5990792Sgshapiro#include <sm/fdset.h> 6038032Speter 6190792Sgshapiro/* structure to describe a daemon or a client */ 6264562Sgshapirostruct daemon 6364562Sgshapiro{ 6464562Sgshapiro int d_socket; /* fd for socket */ 6564562Sgshapiro SOCKADDR d_addr; /* socket for incoming */ 6690792Sgshapiro unsigned short d_port; /* port number */ 6764562Sgshapiro int d_listenqueue; /* size of listen queue */ 6864562Sgshapiro int d_tcprcvbufsize; /* size of TCP receive buffer */ 6964562Sgshapiro int d_tcpsndbufsize; /* size of TCP send buffer */ 7064562Sgshapiro time_t d_refuse_connections_until; 7164562Sgshapiro bool d_firsttime; 7264562Sgshapiro int d_socksize; 7364562Sgshapiro BITMAP256 d_flags; /* flags; see sendmail.h */ 7464562Sgshapiro char *d_mflags; /* flags for use in macro */ 7564562Sgshapiro char *d_name; /* user-supplied name */ 7690792Sgshapiro#if MILTER 7790792Sgshapiro# if _FFR_MILTER_PERDAEMON 7890792Sgshapiro char *d_inputfilterlist; 7990792Sgshapiro struct milter *d_inputfilters[MAXFILTERS]; 8090792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 8190792Sgshapiro#endif /* MILTER */ 8264562Sgshapiro}; 8364562Sgshapiro 8464562Sgshapirotypedef struct daemon DAEMON_T; 8564562Sgshapiro 8690792Sgshapirostatic void connecttimeout __P((void)); 8790792Sgshapirostatic int opendaemonsocket __P((DAEMON_T *, bool)); 8890792Sgshapirostatic unsigned short setupdaemon __P((SOCKADDR *)); 8990792Sgshapirostatic void getrequests_checkdiskspace __P((ENVELOPE *e)); 9064562Sgshapiro 9138032Speter/* 9238032Speter** DAEMON.C -- routines to use when running as a daemon. 9338032Speter** 9438032Speter** This entire file is highly dependent on the 4.2 BSD 9538032Speter** interprocess communication primitives. No attempt has 9638032Speter** been made to make this file portable to Version 7, 9738032Speter** Version 6, MPX files, etc. If you should try such a 9838032Speter** thing yourself, I recommend chucking the entire file 9938032Speter** and starting from scratch. Basic semantics are: 10038032Speter** 10138032Speter** getrequests(e) 10238032Speter** Opens a port and initiates a connection. 10338032Speter** Returns in a child. Must set InChannel and 10438032Speter** OutChannel appropriately. 10538032Speter** clrdaemon() 10638032Speter** Close any open files associated with getting 10738032Speter** the connection; this is used when running the queue, 10838032Speter** etc., to avoid having extra file descriptors during 10938032Speter** the queue run and to avoid confusing the network 11038032Speter** code (if it cares). 11190792Sgshapiro** makeconnection(host, port, mci, e, enough) 11238032Speter** Make a connection to the named host on the given 11390792Sgshapiro** port. Returns zero on success, else an exit status 11490792Sgshapiro** describing the error. 11538032Speter** host_map_lookup(map, hbuf, avp, pstat) 11638032Speter** Convert the entry in hbuf into a canonical form. 11738032Speter*/ 11864562Sgshapiro 11964562Sgshapirostatic DAEMON_T Daemons[MAXDAEMONS]; 12090792Sgshapirostatic int NDaemons = 0; /* actual number of daemons */ 12164562Sgshapiro 12290792Sgshapirostatic time_t NextDiskSpaceCheck = 0; 12364562Sgshapiro 12490792Sgshapiro/* 12538032Speter** GETREQUESTS -- open mail IPC port and get requests. 12638032Speter** 12738032Speter** Parameters: 12838032Speter** e -- the current envelope. 12938032Speter** 13038032Speter** Returns: 13164562Sgshapiro** pointer to flags. 13238032Speter** 13338032Speter** Side Effects: 13438032Speter** Waits until some interesting activity occurs. When 13538032Speter** it does, a child is created to process it, and the 13638032Speter** parent waits for completion. Return from this 13738032Speter** routine is always in the child. The file pointers 13838032Speter** "InChannel" and "OutChannel" should be set to point 13938032Speter** to the communication channel. 14090792Sgshapiro** May restart persistent queue runners if they have ended 14190792Sgshapiro** for some reason. 14238032Speter*/ 14338032Speter 14464562SgshapiroBITMAP256 * 14538032Spetergetrequests(e) 14638032Speter ENVELOPE *e; 14738032Speter{ 14838032Speter int t; 14964562Sgshapiro int idx, curdaemon = -1; 15064562Sgshapiro int i, olddaemon = 0; 15190792Sgshapiro#if XDEBUG 15238032Speter bool j_has_dot; 15390792Sgshapiro#endif /* XDEBUG */ 15442575Speter char status[MAXLINE]; 15564562Sgshapiro SOCKADDR sa; 15664562Sgshapiro SOCKADDR_LEN_T len = sizeof sa; 15794334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 15894334Sgshapiro time_t lastrun; 15994334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 16064562Sgshapiro# if NETUNIX 16142575Speter extern int ControlSocket; 16264562Sgshapiro# endif /* NETUNIX */ 16364562Sgshapiro extern ENVELOPE BlankEnvelope; 16490792Sgshapiro extern bool refuseconnections __P((char *, ENVELOPE *, int, bool)); 16538032Speter 16638032Speter 16790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 16838032Speter { 16964562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 17090792Sgshapiro Daemons[idx].d_firsttime = true; 17164562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 17238032Speter } 17371345Sgshapiro 17438032Speter /* 17538032Speter ** Try to actually open the connection. 17638032Speter */ 17738032Speter 17838032Speter if (tTd(15, 1)) 17964562Sgshapiro { 18090792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 18171345Sgshapiro { 18290792Sgshapiro sm_dprintf("getrequests: daemon %s: port %d\n", 18390792Sgshapiro Daemons[idx].d_name, 18490792Sgshapiro ntohs(Daemons[idx].d_port)); 18571345Sgshapiro } 18664562Sgshapiro } 18738032Speter 18838032Speter /* get a socket for the SMTP connection */ 18990792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 19090792Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true); 19138032Speter 19242575Speter if (opencontrolsocket() < 0) 19342575Speter sm_syslog(LOG_WARNING, NOQID, 19443730Speter "daemon could not open control socket %s: %s", 19590792Sgshapiro ControlSocketName, sm_errstring(errno)); 19642575Speter 19790792Sgshapiro /* If there are any queue runners released reapchild() co-ord's */ 19890792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 19938032Speter 20090792Sgshapiro /* write the pid to file, command line args to syslog */ 20164562Sgshapiro log_sendmail_pid(e); 20238032Speter 20390792Sgshapiro#if XDEBUG 20438032Speter { 20538032Speter char jbuf[MAXHOSTNAMELEN]; 20638032Speter 20738032Speter expand("\201j", jbuf, sizeof jbuf, e); 20838032Speter j_has_dot = strchr(jbuf, '.') != NULL; 20938032Speter } 21090792Sgshapiro#endif /* XDEBUG */ 21138032Speter 21242575Speter /* Add parent process as first item */ 21390792Sgshapiro proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1); 21442575Speter 21538032Speter if (tTd(15, 1)) 21664562Sgshapiro { 21790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 21890792Sgshapiro sm_dprintf("getrequests: daemon %s: %d\n", 21964562Sgshapiro Daemons[idx].d_name, 22064562Sgshapiro Daemons[idx].d_socket); 22164562Sgshapiro } 22238032Speter 22338032Speter for (;;) 22438032Speter { 22538032Speter register pid_t pid; 22638032Speter auto SOCKADDR_LEN_T lotherend; 22790792Sgshapiro bool timedout = false; 22890792Sgshapiro bool control = false; 22964562Sgshapiro int save_errno; 23038032Speter int pipefd[2]; 23190792Sgshapiro time_t now; 23290792Sgshapiro#if STARTTLS 23366494Sgshapiro long seed; 23490792Sgshapiro#endif /* STARTTLS */ 23538032Speter 23638032Speter /* see if we are rejecting connections */ 23790792Sgshapiro (void) sm_blocksignal(SIGALRM); 23864562Sgshapiro 23977349Sgshapiro if (ShutdownRequest != NULL) 24077349Sgshapiro shutdown_daemon(); 24177349Sgshapiro else if (RestartRequest != NULL) 24277349Sgshapiro restart_daemon(); 24390792Sgshapiro else if (RestartWorkGroup) 24490792Sgshapiro restart_marked_work_groups(); 24577349Sgshapiro 24690792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 24771345Sgshapiro { 24890792Sgshapiro /* 24990792Sgshapiro ** XXX do this call outside the loop? 25090792Sgshapiro ** no: refuse_connections may sleep(). 25190792Sgshapiro */ 25271345Sgshapiro 25390792Sgshapiro now = curtime(); 25490792Sgshapiro if (now < Daemons[idx].d_refuse_connections_until) 25564562Sgshapiro continue; 25690792Sgshapiro if (bitnset(D_DISABLE, Daemons[idx].d_flags)) 25790792Sgshapiro continue; 25890792Sgshapiro if (refuseconnections(Daemons[idx].d_name, e, idx, 25990792Sgshapiro curdaemon == idx)) 26038032Speter { 26164562Sgshapiro if (Daemons[idx].d_socket >= 0) 26242575Speter { 26371345Sgshapiro /* close socket so peer fails quickly */ 26471345Sgshapiro (void) close(Daemons[idx].d_socket); 26571345Sgshapiro Daemons[idx].d_socket = -1; 26642575Speter } 26742575Speter 26842575Speter /* refuse connections for next 15 seconds */ 26990792Sgshapiro Daemons[idx].d_refuse_connections_until = now + 15; 27038032Speter } 27164562Sgshapiro else if (Daemons[idx].d_socket < 0 || 27264562Sgshapiro Daemons[idx].d_firsttime) 27342575Speter { 27490792Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel > 8) 27571345Sgshapiro sm_syslog(LOG_INFO, NOQID, 27671345Sgshapiro "accepting connections again for daemon %s", 27771345Sgshapiro Daemons[idx].d_name); 27864562Sgshapiro 27971345Sgshapiro /* arrange to (re)open the socket if needed */ 28090792Sgshapiro (void) opendaemonsocket(&Daemons[idx], false); 28190792Sgshapiro Daemons[idx].d_firsttime = false; 28242575Speter } 28338032Speter } 28438032Speter 28577349Sgshapiro /* May have been sleeping above, check again */ 28677349Sgshapiro if (ShutdownRequest != NULL) 28777349Sgshapiro shutdown_daemon(); 28877349Sgshapiro else if (RestartRequest != NULL) 28977349Sgshapiro restart_daemon(); 29090792Sgshapiro else if (RestartWorkGroup) 29190792Sgshapiro restart_marked_work_groups(); 29277349Sgshapiro 29390792Sgshapiro getrequests_checkdiskspace(e); 29471345Sgshapiro 29590792Sgshapiro#if XDEBUG 29638032Speter /* check for disaster */ 29738032Speter { 29838032Speter char jbuf[MAXHOSTNAMELEN]; 29938032Speter 30038032Speter expand("\201j", jbuf, sizeof jbuf, e); 30138032Speter if (!wordinclass(jbuf, 'w')) 30238032Speter { 30338032Speter dumpstate("daemon lost $j"); 30438032Speter sm_syslog(LOG_ALERT, NOQID, 30564562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 30638032Speter abort(); 30738032Speter } 30838032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 30938032Speter { 31038032Speter dumpstate("daemon $j lost dot"); 31138032Speter sm_syslog(LOG_ALERT, NOQID, 31264562Sgshapiro "daemon process $j lost dot; see syslog"); 31338032Speter abort(); 31438032Speter } 31538032Speter } 31690792Sgshapiro#endif /* XDEBUG */ 31738032Speter 31890792Sgshapiro#if 0 31938032Speter /* 32038032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 32138032Speter ** fix the SVr4 problem. But it seems to have gone away, 32238032Speter ** so is it worth doing this? 32338032Speter */ 32438032Speter 32542575Speter if (DaemonSocket >= 0 && 32690792Sgshapiro SetNonBlocking(DaemonSocket, false) < 0) 32738032Speter log an error here; 32890792Sgshapiro#endif /* 0 */ 32990792Sgshapiro (void) sm_releasesignal(SIGALRM); 33064562Sgshapiro 33138032Speter for (;;) 33238032Speter { 33390792Sgshapiro bool setproc = false; 33442575Speter int highest = -1; 33538032Speter fd_set readfds; 33638032Speter struct timeval timeout; 33738032Speter 33877349Sgshapiro if (ShutdownRequest != NULL) 33977349Sgshapiro shutdown_daemon(); 34077349Sgshapiro else if (RestartRequest != NULL) 34177349Sgshapiro restart_daemon(); 34290792Sgshapiro else if (RestartWorkGroup) 34390792Sgshapiro restart_marked_work_groups(); 34477349Sgshapiro 34538032Speter FD_ZERO(&readfds); 34642575Speter 34790792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 34842575Speter { 34964562Sgshapiro /* wait for a connection */ 35064562Sgshapiro if (Daemons[idx].d_socket >= 0) 35164562Sgshapiro { 35271345Sgshapiro if (!setproc && 35371345Sgshapiro !bitnset(D_ETRNONLY, 35471345Sgshapiro Daemons[idx].d_flags)) 35564562Sgshapiro { 35690792Sgshapiro sm_setproctitle(true, e, 35764562Sgshapiro "accepting connections"); 35890792Sgshapiro setproc = true; 35964562Sgshapiro } 36064562Sgshapiro if (Daemons[idx].d_socket > highest) 36164562Sgshapiro highest = Daemons[idx].d_socket; 36290792Sgshapiro SM_FD_SET(Daemons[idx].d_socket, 36390792Sgshapiro &readfds); 36464562Sgshapiro } 36542575Speter } 36664562Sgshapiro 36790792Sgshapiro#if NETUNIX 36842575Speter if (ControlSocket >= 0) 36942575Speter { 37042575Speter if (ControlSocket > highest) 37142575Speter highest = ControlSocket; 37290792Sgshapiro SM_FD_SET(ControlSocket, &readfds); 37342575Speter } 37490792Sgshapiro#endif /* NETUNIX */ 37564562Sgshapiro 37677349Sgshapiro timeout.tv_sec = 5; 37738032Speter timeout.tv_usec = 0; 37838032Speter 37942575Speter t = select(highest + 1, FDSET_CAST &readfds, 38064562Sgshapiro NULL, NULL, &timeout); 38142575Speter 38277349Sgshapiro /* Did someone signal while waiting? */ 38377349Sgshapiro if (ShutdownRequest != NULL) 38477349Sgshapiro shutdown_daemon(); 38577349Sgshapiro else if (RestartRequest != NULL) 38677349Sgshapiro restart_daemon(); 38790792Sgshapiro else if (RestartWorkGroup) 38890792Sgshapiro restart_marked_work_groups(); 38971345Sgshapiro 39071345Sgshapiro 39177349Sgshapiro 39290792Sgshapiro curdaemon = -1; 39390792Sgshapiro if (doqueuerun()) 39494334Sgshapiro { 39590792Sgshapiro (void) runqueue(true, false, false, false); 39694334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 39794334Sgshapiro lastrun = now; 39894334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 39994334Sgshapiro } 40094334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 40194334Sgshapiro else if (QueueIntvl > 0 && 40294334Sgshapiro lastrun + QueueIntvl + 60 < now) 40394334Sgshapiro { 40471345Sgshapiro 40594334Sgshapiro /* 40694334Sgshapiro ** set lastrun unconditionally to avoid 40794334Sgshapiro ** calling checkqueuerunner() all the time. 40894334Sgshapiro ** That's also why we currently ignore the 40994334Sgshapiro ** result of the function call. 41094334Sgshapiro */ 41194334Sgshapiro 41294334Sgshapiro (void) checkqueuerunner(); 41394334Sgshapiro lastrun = now; 41494334Sgshapiro } 41594334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 41694334Sgshapiro 41742575Speter if (t <= 0) 41842575Speter { 41990792Sgshapiro timedout = true; 42042575Speter break; 42142575Speter } 42238032Speter 42390792Sgshapiro control = false; 42438032Speter errno = 0; 42564562Sgshapiro 42664562Sgshapiro /* look "round-robin" for an active socket */ 42790792Sgshapiro if ((idx = olddaemon + 1) >= NDaemons) 42864562Sgshapiro idx = 0; 42990792Sgshapiro for (i = 0; i < NDaemons; i++) 43042575Speter { 43164562Sgshapiro if (Daemons[idx].d_socket >= 0 && 43290792Sgshapiro SM_FD_ISSET(Daemons[idx].d_socket, 43390792Sgshapiro &readfds)) 43464562Sgshapiro { 43564562Sgshapiro lotherend = Daemons[idx].d_socksize; 43673188Sgshapiro memset(&RealHostAddr, '\0', 43773188Sgshapiro sizeof RealHostAddr); 43864562Sgshapiro t = accept(Daemons[idx].d_socket, 43964562Sgshapiro (struct sockaddr *)&RealHostAddr, 44064562Sgshapiro &lotherend); 44173188Sgshapiro 44273188Sgshapiro /* 44373188Sgshapiro ** If remote side closes before 44473188Sgshapiro ** accept() finishes, sockaddr 44573188Sgshapiro ** might not be fully filled in. 44673188Sgshapiro */ 44773188Sgshapiro 44873188Sgshapiro if (t >= 0 && 44973188Sgshapiro (lotherend == 0 || 45073188Sgshapiro# ifdef BSD4_4_SOCKADDR 45173188Sgshapiro RealHostAddr.sa.sa_len == 0 || 45273188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 45373188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 45473188Sgshapiro { 45573188Sgshapiro (void) close(t); 45673188Sgshapiro t = -1; 45773188Sgshapiro errno = EINVAL; 45873188Sgshapiro } 45964562Sgshapiro olddaemon = curdaemon = idx; 46064562Sgshapiro break; 46164562Sgshapiro } 46290792Sgshapiro if (++idx >= NDaemons) 46364562Sgshapiro idx = 0; 46442575Speter } 46590792Sgshapiro#if NETUNIX 46664562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 46790792Sgshapiro SM_FD_ISSET(ControlSocket, &readfds)) 46842575Speter { 46942575Speter struct sockaddr_un sa_un; 47042575Speter 47142575Speter lotherend = sizeof sa_un; 47273188Sgshapiro memset(&sa_un, '\0', sizeof sa_un); 47342575Speter t = accept(ControlSocket, 47442575Speter (struct sockaddr *)&sa_un, 47542575Speter &lotherend); 47673188Sgshapiro 47773188Sgshapiro /* 47873188Sgshapiro ** If remote side closes before 47973188Sgshapiro ** accept() finishes, sockaddr 48073188Sgshapiro ** might not be fully filled in. 48173188Sgshapiro */ 48273188Sgshapiro 48373188Sgshapiro if (t >= 0 && 48473188Sgshapiro (lotherend == 0 || 48573188Sgshapiro# ifdef BSD4_4_SOCKADDR 48673188Sgshapiro sa_un.sun_len == 0 || 48773188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 48873188Sgshapiro sa_un.sun_family != AF_UNIX)) 48973188Sgshapiro { 49073188Sgshapiro (void) close(t); 49173188Sgshapiro t = -1; 49273188Sgshapiro errno = EINVAL; 49373188Sgshapiro } 49473188Sgshapiro if (t >= 0) 49590792Sgshapiro control = true; 49642575Speter } 49790792Sgshapiro#else /* NETUNIX */ 49871345Sgshapiro if (curdaemon == -1) 49971345Sgshapiro { 50071345Sgshapiro /* No daemon to service */ 50171345Sgshapiro continue; 50271345Sgshapiro } 50390792Sgshapiro#endif /* NETUNIX */ 50438032Speter if (t >= 0 || errno != EINTR) 50538032Speter break; 50638032Speter } 50742575Speter if (timedout) 50842575Speter { 50990792Sgshapiro timedout = false; 51042575Speter continue; 51142575Speter } 51264562Sgshapiro save_errno = errno; 51390792Sgshapiro (void) sm_blocksignal(SIGALRM); 51438032Speter if (t < 0) 51538032Speter { 51664562Sgshapiro errno = save_errno; 51738032Speter syserr("getrequests: accept"); 51838032Speter 51938032Speter /* arrange to re-open the socket next time around */ 52064562Sgshapiro (void) close(Daemons[curdaemon].d_socket); 52164562Sgshapiro Daemons[curdaemon].d_socket = -1; 52290792Sgshapiro#if SO_REUSEADDR_IS_BROKEN 52364562Sgshapiro /* 52464562Sgshapiro ** Give time for bound socket to be released. 52564562Sgshapiro ** This creates a denial-of-service if you can 52664562Sgshapiro ** force accept() to fail on affected systems. 52764562Sgshapiro */ 52864562Sgshapiro 52990792Sgshapiro Daemons[curdaemon].d_refuse_connections_until = curtime() + 15; 53090792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */ 53138032Speter continue; 53238032Speter } 53338032Speter 53464562Sgshapiro if (!control) 53564562Sgshapiro { 53664562Sgshapiro /* set some daemon related macros */ 53764562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 53864562Sgshapiro { 53964562Sgshapiro case AF_UNSPEC: 54090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54190792Sgshapiro macid("{daemon_family}"), "unspec"); 54264562Sgshapiro break; 54390792Sgshapiro#if _FFR_DAEMON_NETUNIX 54490792Sgshapiro# if NETUNIX 54590792Sgshapiro case AF_UNIX: 54690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54790792Sgshapiro macid("{daemon_family}"), "local"); 54890792Sgshapiro break; 54990792Sgshapiro# endif /* NETUNIX */ 55090792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 55190792Sgshapiro#if NETINET 55264562Sgshapiro case AF_INET: 55390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55490792Sgshapiro macid("{daemon_family}"), "inet"); 55564562Sgshapiro break; 55690792Sgshapiro#endif /* NETINET */ 55790792Sgshapiro#if NETINET6 55864562Sgshapiro case AF_INET6: 55990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56090792Sgshapiro macid("{daemon_family}"), "inet6"); 56164562Sgshapiro break; 56290792Sgshapiro#endif /* NETINET6 */ 56390792Sgshapiro#if NETISO 56464562Sgshapiro case AF_ISO: 56590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56690792Sgshapiro macid("{daemon_family}"), "iso"); 56764562Sgshapiro break; 56890792Sgshapiro#endif /* NETISO */ 56990792Sgshapiro#if NETNS 57064562Sgshapiro case AF_NS: 57190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 57290792Sgshapiro macid("{daemon_family}"), "ns"); 57364562Sgshapiro break; 57490792Sgshapiro#endif /* NETNS */ 57590792Sgshapiro#if NETX25 57664562Sgshapiro case AF_CCITT: 57790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 57890792Sgshapiro macid("{daemon_family}"), "x.25"); 57964562Sgshapiro break; 58090792Sgshapiro#endif /* NETX25 */ 58164562Sgshapiro } 58290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 58390792Sgshapiro macid("{daemon_name}"), 58490792Sgshapiro Daemons[curdaemon].d_name); 58564562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 58690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 58790792Sgshapiro macid("{daemon_flags}"), 58890792Sgshapiro Daemons[curdaemon].d_mflags); 58964562Sgshapiro else 59090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 59190792Sgshapiro macid("{daemon_flags}"), ""); 59264562Sgshapiro } 59364562Sgshapiro 59438032Speter /* 59538032Speter ** Create a subprocess to process the mail. 59638032Speter */ 59738032Speter 59838032Speter if (tTd(15, 2)) 59990792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 60038032Speter 60138032Speter /* 60290792Sgshapiro ** Advance state of PRNG. 60390792Sgshapiro ** This is necessary because otherwise all child processes 60464562Sgshapiro ** will produce the same PRN sequence and hence the selection 60564562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 60664562Sgshapiro ** are not "really" random. 60764562Sgshapiro */ 60890792Sgshapiro#if STARTTLS 60990792Sgshapiro /* XXX get some better "random" data? */ 61066494Sgshapiro seed = get_random(); 61190792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 61290792Sgshapiro sizeof NextDiskSpaceCheck); 61390792Sgshapiro RAND_seed((void *) &now, sizeof now); 61466494Sgshapiro RAND_seed((void *) &seed, sizeof seed); 61590792Sgshapiro#else /* STARTTLS */ 61664562Sgshapiro (void) get_random(); 61790792Sgshapiro#endif /* STARTTLS */ 61864562Sgshapiro 61990792Sgshapiro#if NAMED_BIND 62064562Sgshapiro /* 62190792Sgshapiro ** Update MX records for FallBackMX. 62290792Sgshapiro ** Let's hope this is fast otherwise we screw up the 62390792Sgshapiro ** response time. 62490792Sgshapiro */ 62590792Sgshapiro 62690792Sgshapiro if (FallBackMX != NULL) 62790792Sgshapiro (void) getfallbackmxrr(FallBackMX); 62890792Sgshapiro#endif /* NAMED_BIND */ 62990792Sgshapiro 63090792Sgshapiro#if !PROFILING 63190792Sgshapiro /* 63238032Speter ** Create a pipe to keep the child from writing to the 63338032Speter ** socket until after the parent has closed it. Otherwise 63438032Speter ** the parent may hang if the child has closed it first. 63538032Speter */ 63638032Speter 63738032Speter if (pipe(pipefd) < 0) 63838032Speter pipefd[0] = pipefd[1] = -1; 63938032Speter 64090792Sgshapiro (void) sm_blocksignal(SIGCHLD); 64138032Speter pid = fork(); 64238032Speter if (pid < 0) 64338032Speter { 64438032Speter syserr("daemon: cannot fork"); 64538032Speter if (pipefd[0] != -1) 64638032Speter { 64738032Speter (void) close(pipefd[0]); 64838032Speter (void) close(pipefd[1]); 64938032Speter } 65090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 65164562Sgshapiro (void) sleep(10); 65238032Speter (void) close(t); 65338032Speter continue; 65438032Speter } 65590792Sgshapiro 65690792Sgshapiro#else /* !PROFILING */ 65771345Sgshapiro pid = 0; 65890792Sgshapiro#endif /* !PROFILING */ 65938032Speter 66038032Speter if (pid == 0) 66138032Speter { 66238032Speter char *p; 66390792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 66438032Speter 66538032Speter /* 66638032Speter ** CHILD -- return to caller. 66738032Speter ** Collect verified idea of sending host. 66838032Speter ** Verify calling user id if possible here. 66938032Speter */ 67038032Speter 67177349Sgshapiro /* Reset global flags */ 67277349Sgshapiro RestartRequest = NULL; 67390792Sgshapiro RestartWorkGroup = false; 67477349Sgshapiro ShutdownRequest = NULL; 67577349Sgshapiro PendingSignal = 0; 67690792Sgshapiro CurrentPid = getpid(); 67777349Sgshapiro 67890792Sgshapiro (void) sm_releasesignal(SIGALRM); 67990792Sgshapiro (void) sm_releasesignal(SIGCHLD); 68090792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 68190792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 68290792Sgshapiro (void) sm_signal(SIGTERM, intsig); 68377349Sgshapiro 68490792Sgshapiro /* turn on profiling */ 68590792Sgshapiro /* SM_PROF(0); */ 68690792Sgshapiro 68790792Sgshapiro /* 68890792Sgshapiro ** Initialize exception stack and default exception 68990792Sgshapiro ** handler for child process. 69090792Sgshapiro */ 69190792Sgshapiro 69290792Sgshapiro sm_exc_newthread(fatal_error); 69390792Sgshapiro 69464562Sgshapiro if (!control) 69564562Sgshapiro { 69690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 69790792Sgshapiro macid("{daemon_addr}"), 69890792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 69990792Sgshapiro (void) sm_snprintf(status, sizeof status, "%d", 70064562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 70190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 70290792Sgshapiro macid("{daemon_port}"), status); 70364562Sgshapiro } 70464562Sgshapiro 70590792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 70664562Sgshapiro { 70764562Sgshapiro if (Daemons[idx].d_socket >= 0) 70864562Sgshapiro (void) close(Daemons[idx].d_socket); 70980785Sgshapiro Daemons[idx].d_socket = -1; 71064562Sgshapiro } 71142575Speter clrcontrol(); 71238032Speter 71364562Sgshapiro /* Avoid SMTP daemon actions if control command */ 71464562Sgshapiro if (control) 71564562Sgshapiro { 71664562Sgshapiro /* Add control socket process */ 71790792Sgshapiro proc_list_add(CurrentPid, 71890792Sgshapiro "console socket child", 71990792Sgshapiro PROC_CONTROL_CHILD, 0, -1); 72064562Sgshapiro } 72164562Sgshapiro else 72264562Sgshapiro { 72364562Sgshapiro proc_list_clear(); 72442575Speter 72590792Sgshapiro /* clean up background delivery children */ 72690792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 72790792Sgshapiro 72864562Sgshapiro /* Add parent process as first child item */ 72990792Sgshapiro proc_list_add(CurrentPid, "daemon child", 73090792Sgshapiro PROC_DAEMON_CHILD, 0, -1); 73138032Speter 73264562Sgshapiro /* don't schedule queue runs if ETRN */ 73364562Sgshapiro QueueIntvl = 0; 73438032Speter 73590792Sgshapiro sm_setproctitle(true, e, "startup with %s", 73664562Sgshapiro anynet_ntoa(&RealHostAddr)); 73764562Sgshapiro } 73864562Sgshapiro 73990792Sgshapiro#if !PROFILING 74038032Speter if (pipefd[0] != -1) 74138032Speter { 74238032Speter auto char c; 74338032Speter 74438032Speter /* 74538032Speter ** Wait for the parent to close the write end 74638032Speter ** of the pipe, which we will see as an EOF. 74738032Speter ** This guarantees that we won't write to the 74838032Speter ** socket until after the parent has closed 74938032Speter ** the pipe. 75038032Speter */ 75138032Speter 75238032Speter /* close the write end of the pipe */ 75338032Speter (void) close(pipefd[1]); 75438032Speter 75538032Speter /* we shouldn't be interrupted, but ... */ 75638032Speter while (read(pipefd[0], &c, 1) < 0 && 75738032Speter errno == EINTR) 75838032Speter continue; 75938032Speter (void) close(pipefd[0]); 76038032Speter } 76190792Sgshapiro#endif /* !PROFILING */ 76238032Speter 76364562Sgshapiro /* control socket processing */ 76464562Sgshapiro if (control) 76564562Sgshapiro { 76664562Sgshapiro control_command(t, e); 76764562Sgshapiro /* NOTREACHED */ 76864562Sgshapiro exit(EX_SOFTWARE); 76964562Sgshapiro } 77064562Sgshapiro 77138032Speter /* determine host name */ 77238032Speter p = hostnamebyanyaddr(&RealHostAddr); 77390792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 77438032Speter p[MAXNAME] = '\0'; 77538032Speter RealHostName = newstr(p); 77664562Sgshapiro if (RealHostName[0] == '[') 77764562Sgshapiro { 77890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 77990792Sgshapiro macid("{client_resolve}"), 78090792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 78164562Sgshapiro } 78264562Sgshapiro else 78390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 78490792Sgshapiro macid("{client_resolve}"), "OK"); 78590792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 78694334Sgshapiro markstats(e, NULL, STATS_CONNECT); 78738032Speter 78890792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 78990792Sgshapiro SM_TIME_DEFAULT, 79090792Sgshapiro (void *) &t, 79190792Sgshapiro SM_IO_RDONLY, 79290792Sgshapiro NULL)) == NULL || 79338032Speter (t = dup(t)) < 0 || 79490792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 79590792Sgshapiro SM_TIME_DEFAULT, 79690792Sgshapiro (void *) &t, 79790792Sgshapiro SM_IO_WRONLY, 79890792Sgshapiro NULL)) == NULL) 79938032Speter { 80090792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 80190792Sgshapiro t); 80290792Sgshapiro finis(false, true, EX_OK); 80338032Speter } 80490792Sgshapiro sm_io_automode(inchannel, outchannel); 80538032Speter 80638032Speter InChannel = inchannel; 80738032Speter OutChannel = outchannel; 80890792Sgshapiro DisConnected = false; 80938032Speter 81090792Sgshapiro#if XLA 81138032Speter if (!xla_host_ok(RealHostName)) 81238032Speter { 81364562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 81490792Sgshapiro finis(false, true, EX_OK); 81538032Speter } 81690792Sgshapiro#endif /* XLA */ 81764562Sgshapiro /* find out name for interface of connection */ 81890792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 81990792Sgshapiro NULL), &sa.sa, &len) == 0) 82064562Sgshapiro { 82164562Sgshapiro p = hostnamebyanyaddr(&sa); 82264562Sgshapiro if (tTd(15, 9)) 82390792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 82490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 82590792Sgshapiro macid("{if_name}"), p); 82664562Sgshapiro 82790792Sgshapiro /* 82890792Sgshapiro ** Do this only if it is not the loopback 82990792Sgshapiro ** interface. 83090792Sgshapiro */ 83190792Sgshapiro 83264562Sgshapiro if (!isloopback(sa)) 83364562Sgshapiro { 83490792Sgshapiro char *addr; 83590792Sgshapiro char family[5]; 83690792Sgshapiro 83790792Sgshapiro addr = anynet_ntoa(&sa); 83890792Sgshapiro (void) sm_snprintf(family, 83990792Sgshapiro sizeof(family), 84090792Sgshapiro "%d", sa.sa.sa_family); 84190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 84290792Sgshapiro A_TEMP, 84390792Sgshapiro macid("{if_addr}"), addr); 84490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 84590792Sgshapiro A_TEMP, 84690792Sgshapiro macid("{if_family}"), family); 84764562Sgshapiro if (tTd(15, 7)) 84890792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 84990792Sgshapiro addr, family); 85064562Sgshapiro } 85164562Sgshapiro else 85264562Sgshapiro { 85390792Sgshapiro macdefine(&BlankEnvelope.e_macro, 85490792Sgshapiro A_PERM, 85590792Sgshapiro macid("{if_addr}"), NULL); 85690792Sgshapiro macdefine(&BlankEnvelope.e_macro, 85790792Sgshapiro A_PERM, 85890792Sgshapiro macid("{if_family}"), NULL); 85964562Sgshapiro } 86064562Sgshapiro } 86164562Sgshapiro else 86264562Sgshapiro { 86364562Sgshapiro if (tTd(15, 7)) 86490792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 86590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 86690792Sgshapiro macid("{if_name}"), NULL); 86790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 86890792Sgshapiro macid("{if_addr}"), NULL); 86990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 87090792Sgshapiro macid("{if_family}"), NULL); 87164562Sgshapiro } 87238032Speter break; 87338032Speter } 87438032Speter 87538032Speter /* parent -- keep track of children */ 87664562Sgshapiro if (control) 87764562Sgshapiro { 87890792Sgshapiro (void) sm_snprintf(status, sizeof status, 87990792Sgshapiro "control socket server child"); 88090792Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1); 88164562Sgshapiro } 88264562Sgshapiro else 88364562Sgshapiro { 88490792Sgshapiro (void) sm_snprintf(status, sizeof status, 88590792Sgshapiro "SMTP server child for %s", 88690792Sgshapiro anynet_ntoa(&RealHostAddr)); 88790792Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1); 88864562Sgshapiro } 88990792Sgshapiro (void) sm_releasesignal(SIGCHLD); 89038032Speter 89138032Speter /* close the read end of the synchronization pipe */ 89238032Speter if (pipefd[0] != -1) 89364562Sgshapiro { 89438032Speter (void) close(pipefd[0]); 89564562Sgshapiro pipefd[0] = -1; 89664562Sgshapiro } 89738032Speter 89838032Speter /* close the port so that others will hang (for a while) */ 89938032Speter (void) close(t); 90038032Speter 90138032Speter /* release the child by closing the read end of the sync pipe */ 90238032Speter if (pipefd[1] != -1) 90364562Sgshapiro { 90438032Speter (void) close(pipefd[1]); 90564562Sgshapiro pipefd[1] = -1; 90664562Sgshapiro } 90738032Speter } 90890792Sgshapiro if (tTd(15, 2)) 90990792Sgshapiro sm_dprintf("getreq: returning\n"); 91064562Sgshapiro 91190792Sgshapiro#if MILTER 91290792Sgshapiro# if _FFR_MILTER_PERDAEMON 91390792Sgshapiro /* set the filters for this daemon */ 91490792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 91590792Sgshapiro { 91690792Sgshapiro for (i = 0; 91790792Sgshapiro (Daemons[curdaemon].d_inputfilters[i] != NULL && 91890792Sgshapiro i < MAXFILTERS); 91990792Sgshapiro i++) 92090792Sgshapiro { 92190792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 92290792Sgshapiro } 92390792Sgshapiro if (i < MAXFILTERS) 92490792Sgshapiro InputFilters[i] = NULL; 92590792Sgshapiro } 92690792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 92790792Sgshapiro#endif /* MILTER */ 92864562Sgshapiro return &Daemons[curdaemon].d_flags; 92938032Speter} 93090792Sgshapiro 93190792Sgshapiro/* 93290792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 93390792Sgshapiro** 93490792Sgshapiro** Parameters: 93590792Sgshapiro** e -- envelope. 93690792Sgshapiro** 93790792Sgshapiro** Returns: 93890792Sgshapiro** none. 93990792Sgshapiro** 94090792Sgshapiro** Side Effects: 94190792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 94290792Sgshapiro*/ 94390792Sgshapiro 94490792Sgshapirostatic void 94590792Sgshapirogetrequests_checkdiskspace(e) 94690792Sgshapiro ENVELOPE *e; 94790792Sgshapiro{ 94890792Sgshapiro bool logged = false; 94990792Sgshapiro int idx; 95090792Sgshapiro time_t now; 95190792Sgshapiro 95290792Sgshapiro now = curtime(); 95390792Sgshapiro if (now < NextDiskSpaceCheck) 95490792Sgshapiro return; 95590792Sgshapiro 95690792Sgshapiro /* Check if there is available disk space in all queue groups. */ 95790792Sgshapiro if (!enoughdiskspace(0, NULL)) 95890792Sgshapiro { 95990792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 96090792Sgshapiro { 96190792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 96290792Sgshapiro continue; 96390792Sgshapiro 96490792Sgshapiro /* log only if not logged before */ 96590792Sgshapiro if (!logged) 96690792Sgshapiro { 96790792Sgshapiro if (LogLevel > 8) 96890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 96990792Sgshapiro "rejecting new messages: min free: %ld", 97090792Sgshapiro MinBlocksFree); 97190792Sgshapiro sm_setproctitle(true, e, 97290792Sgshapiro "rejecting new messages: min free: %ld", 97390792Sgshapiro MinBlocksFree); 97490792Sgshapiro logged = true; 97590792Sgshapiro } 97690792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 97790792Sgshapiro } 97890792Sgshapiro } 97990792Sgshapiro else 98090792Sgshapiro { 98190792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 98290792Sgshapiro { 98390792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 98490792Sgshapiro continue; 98590792Sgshapiro 98690792Sgshapiro /* log only if not logged before */ 98790792Sgshapiro if (!logged) 98890792Sgshapiro { 98990792Sgshapiro if (LogLevel > 8) 99090792Sgshapiro sm_syslog(LOG_INFO, NOQID, 99190792Sgshapiro "accepting new messages (again)"); 99290792Sgshapiro logged = true; 99390792Sgshapiro } 99490792Sgshapiro 99590792Sgshapiro /* title will be set later */ 99690792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 99790792Sgshapiro } 99890792Sgshapiro } 99990792Sgshapiro 100090792Sgshapiro /* only check disk space once a minute */ 100190792Sgshapiro NextDiskSpaceCheck = now + 60; 100290792Sgshapiro} 100390792Sgshapiro 100490792Sgshapiro/* 100564562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 100638032Speter** 100764562Sgshapiro** Deals with setting all appropriate options. 100838032Speter** 100938032Speter** Parameters: 101064562Sgshapiro** d -- the structure for the daemon to open. 101138032Speter** firsttime -- set if this is the initial open. 101238032Speter** 101338032Speter** Returns: 101438032Speter** Size in bytes of the daemon socket addr. 101538032Speter** 101638032Speter** Side Effects: 101738032Speter** Leaves DaemonSocket set to the open socket. 101838032Speter** Exits if the socket cannot be created. 101938032Speter*/ 102038032Speter 102190792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 102238032Speter 102364562Sgshapirostatic int 102464562Sgshapiroopendaemonsocket(d, firsttime) 102590792Sgshapiro DAEMON_T *d; 102638032Speter bool firsttime; 102738032Speter{ 102838032Speter int on = 1; 102964562Sgshapiro int fdflags; 103064562Sgshapiro SOCKADDR_LEN_T socksize = 0; 103138032Speter int ntries = 0; 103264562Sgshapiro int save_errno; 103338032Speter 103438032Speter if (tTd(15, 2)) 103590792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 103638032Speter 103738032Speter do 103838032Speter { 103938032Speter if (ntries > 0) 104064562Sgshapiro (void) sleep(5); 104164562Sgshapiro if (firsttime || d->d_socket < 0) 104238032Speter { 104390792Sgshapiro#if _FFR_DAEMON_NETUNIX 104490792Sgshapiro# if NETUNIX 104590792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 104690792Sgshapiro { 104790792Sgshapiro int rval; 104890792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 104990792Sgshapiro 105090792Sgshapiro /* if not safe, don't use it */ 105190792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 105290792Sgshapiro RunAsUid, RunAsGid, 105390792Sgshapiro RunAsUserName, sff, 105490792Sgshapiro S_IRUSR|S_IWUSR, NULL); 105590792Sgshapiro if (rval != 0) 105690792Sgshapiro { 105790792Sgshapiro save_errno = errno; 105890792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 105990792Sgshapiro d->d_name, 106090792Sgshapiro d->d_addr.sunix.sun_path); 106190792Sgshapiro goto fail; 106290792Sgshapiro } 106390792Sgshapiro 106490792Sgshapiro /* Don't try to overtake an existing socket */ 106590792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 106690792Sgshapiro } 106790792Sgshapiro# endif /* NETUNIX */ 106890792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */ 106964562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 107064562Sgshapiro SOCK_STREAM, 0); 107164562Sgshapiro if (d->d_socket < 0) 107238032Speter { 107364562Sgshapiro save_errno = errno; 107490792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 107590792Sgshapiro d->d_name); 107690792Sgshapiro fail: 107790792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 107890792Sgshapiro (!transienterror(save_errno) || 107990792Sgshapiro ntries >= MAXOPENTRIES - 1)) 108090792Sgshapiro { 108190792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 108290792Sgshapiro d->d_name); 108390792Sgshapiro setbitn(D_DISABLE, d->d_flags); 108490792Sgshapiro d->d_socket = -1; 108590792Sgshapiro return -1; 108690792Sgshapiro } 108738032Speter severe: 108838032Speter if (LogLevel > 0) 108938032Speter sm_syslog(LOG_ALERT, NOQID, 109090792Sgshapiro "daemon %s: problem creating SMTP socket", 109190792Sgshapiro d->d_name); 109264562Sgshapiro d->d_socket = -1; 109338032Speter continue; 109438032Speter } 109538032Speter 109638032Speter /* turn on network debugging? */ 109738032Speter if (tTd(15, 101)) 109864562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 109938032Speter SO_DEBUG, (char *)&on, 110038032Speter sizeof on); 110138032Speter 110264562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 110338032Speter SO_REUSEADDR, (char *)&on, sizeof on); 110464562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 110538032Speter SO_KEEPALIVE, (char *)&on, sizeof on); 110638032Speter 110790792Sgshapiro#ifdef SO_RCVBUF 110864562Sgshapiro if (d->d_tcprcvbufsize > 0) 110938032Speter { 111064562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 111138032Speter SO_RCVBUF, 111264562Sgshapiro (char *) &d->d_tcprcvbufsize, 111364562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 111464562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 111538032Speter } 111690792Sgshapiro#endif /* SO_RCVBUF */ 111790792Sgshapiro#ifdef SO_SNDBUF 111864562Sgshapiro if (d->d_tcpsndbufsize > 0) 111964562Sgshapiro { 112064562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 112164562Sgshapiro SO_SNDBUF, 112264562Sgshapiro (char *) &d->d_tcpsndbufsize, 112364562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 112464562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 112564562Sgshapiro } 112690792Sgshapiro#endif /* SO_SNDBUF */ 112738032Speter 112864562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 112964562Sgshapiro fcntl(d->d_socket, F_SETFD, 113064562Sgshapiro fdflags | FD_CLOEXEC) == -1) 113138032Speter { 113264562Sgshapiro save_errno = errno; 113364562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 113464562Sgshapiro d->d_name, 113564562Sgshapiro fdflags == -1 ? "get" : "set", 113690792Sgshapiro sm_errstring(save_errno)); 113764562Sgshapiro (void) close(d->d_socket); 113864562Sgshapiro goto severe; 113964562Sgshapiro } 114064562Sgshapiro 114164562Sgshapiro switch (d->d_addr.sa.sa_family) 114264562Sgshapiro { 114390792Sgshapiro#if _FFR_DAEMON_NETUNIX 114490792Sgshapiro# ifdef NETUNIX 114590792Sgshapiro case AF_UNIX: 114690792Sgshapiro socksize = sizeof d->d_addr.sunix; 114790792Sgshapiro break; 114890792Sgshapiro# endif /* NETUNIX */ 114990792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 115090792Sgshapiro#if NETINET 115138032Speter case AF_INET: 115264562Sgshapiro socksize = sizeof d->d_addr.sin; 115338032Speter break; 115490792Sgshapiro#endif /* NETINET */ 115538032Speter 115690792Sgshapiro#if NETINET6 115764562Sgshapiro case AF_INET6: 115864562Sgshapiro socksize = sizeof d->d_addr.sin6; 115964562Sgshapiro break; 116090792Sgshapiro#endif /* NETINET6 */ 116164562Sgshapiro 116290792Sgshapiro#if NETISO 116338032Speter case AF_ISO: 116464562Sgshapiro socksize = sizeof d->d_addr.siso; 116538032Speter break; 116690792Sgshapiro#endif /* NETISO */ 116738032Speter 116838032Speter default: 116964562Sgshapiro socksize = sizeof d->d_addr; 117038032Speter break; 117138032Speter } 117238032Speter 117364562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 117438032Speter { 117538032Speter /* probably another daemon already */ 117664562Sgshapiro save_errno = errno; 117764562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 117864562Sgshapiro d->d_name); 117964562Sgshapiro (void) close(d->d_socket); 118090792Sgshapiro goto fail; 118138032Speter } 118238032Speter } 118364562Sgshapiro if (!firsttime && 118464562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 118538032Speter { 118664562Sgshapiro save_errno = errno; 118764562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 118864562Sgshapiro d->d_name); 118964562Sgshapiro (void) close(d->d_socket); 119038032Speter goto severe; 119138032Speter } 119238032Speter return socksize; 119364562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 119464562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 119564562Sgshapiro d->d_name); 119664562Sgshapiro /* NOTREACHED */ 119738032Speter return -1; /* avoid compiler warning on IRIX */ 119838032Speter} 119990792Sgshapiro/* 120064562Sgshapiro** SETUPDAEMON -- setup socket for daemon 120164562Sgshapiro** 120264562Sgshapiro** Parameters: 120364562Sgshapiro** daemonaddr -- socket for daemon 120464562Sgshapiro** 120564562Sgshapiro** Returns: 120664562Sgshapiro** port number on which daemon should run 120764562Sgshapiro** 120864562Sgshapiro*/ 120990792Sgshapiro 121090792Sgshapirostatic unsigned short 121164562Sgshapirosetupdaemon(daemonaddr) 121264562Sgshapiro SOCKADDR *daemonaddr; 121364562Sgshapiro{ 121490792Sgshapiro unsigned short port; 121564562Sgshapiro 121664562Sgshapiro /* 121764562Sgshapiro ** Set up the address for the mailer. 121864562Sgshapiro */ 121964562Sgshapiro 122064562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 122164562Sgshapiro { 122264562Sgshapiro memset(daemonaddr, '\0', sizeof *daemonaddr); 122390792Sgshapiro#if NETINET 122464562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 122590792Sgshapiro#endif /* NETINET */ 122664562Sgshapiro } 122764562Sgshapiro 122864562Sgshapiro switch (daemonaddr->sa.sa_family) 122964562Sgshapiro { 123090792Sgshapiro#if NETINET 123164562Sgshapiro case AF_INET: 123264562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 123364562Sgshapiro daemonaddr->sin.sin_addr.s_addr = INADDR_ANY; 123464562Sgshapiro port = daemonaddr->sin.sin_port; 123564562Sgshapiro break; 123690792Sgshapiro#endif /* NETINET */ 123764562Sgshapiro 123890792Sgshapiro#if NETINET6 123964562Sgshapiro case AF_INET6: 124064562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 124164562Sgshapiro daemonaddr->sin6.sin6_addr = in6addr_any; 124264562Sgshapiro port = daemonaddr->sin6.sin6_port; 124364562Sgshapiro break; 124490792Sgshapiro#endif /* NETINET6 */ 124564562Sgshapiro 124664562Sgshapiro default: 124764562Sgshapiro /* unknown protocol */ 124864562Sgshapiro port = 0; 124964562Sgshapiro break; 125064562Sgshapiro } 125164562Sgshapiro if (port == 0) 125264562Sgshapiro { 125390792Sgshapiro#ifdef NO_GETSERVBYNAME 125464562Sgshapiro port = htons(25); 125590792Sgshapiro#else /* NO_GETSERVBYNAME */ 125664562Sgshapiro { 125764562Sgshapiro register struct servent *sp; 125864562Sgshapiro 125964562Sgshapiro sp = getservbyname("smtp", "tcp"); 126064562Sgshapiro if (sp == NULL) 126164562Sgshapiro { 126264562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 126364562Sgshapiro port = htons(25); 126464562Sgshapiro } 126564562Sgshapiro else 126664562Sgshapiro port = sp->s_port; 126764562Sgshapiro } 126890792Sgshapiro#endif /* NO_GETSERVBYNAME */ 126964562Sgshapiro } 127064562Sgshapiro 127164562Sgshapiro switch (daemonaddr->sa.sa_family) 127264562Sgshapiro { 127390792Sgshapiro#if NETINET 127464562Sgshapiro case AF_INET: 127564562Sgshapiro daemonaddr->sin.sin_port = port; 127664562Sgshapiro break; 127790792Sgshapiro#endif /* NETINET */ 127864562Sgshapiro 127990792Sgshapiro#if NETINET6 128064562Sgshapiro case AF_INET6: 128164562Sgshapiro daemonaddr->sin6.sin6_port = port; 128264562Sgshapiro break; 128390792Sgshapiro#endif /* NETINET6 */ 128464562Sgshapiro 128564562Sgshapiro default: 128664562Sgshapiro /* unknown protocol */ 128764562Sgshapiro break; 128864562Sgshapiro } 128990792Sgshapiro return port; 129064562Sgshapiro} 129190792Sgshapiro/* 129238032Speter** CLRDAEMON -- reset the daemon connection 129338032Speter** 129438032Speter** Parameters: 129538032Speter** none. 129638032Speter** 129738032Speter** Returns: 129838032Speter** none. 129938032Speter** 130038032Speter** Side Effects: 130138032Speter** releases any resources used by the passive daemon. 130238032Speter*/ 130338032Speter 130438032Spetervoid 130538032Speterclrdaemon() 130638032Speter{ 130764562Sgshapiro int i; 130864562Sgshapiro 130990792Sgshapiro for (i = 0; i < NDaemons; i++) 131064562Sgshapiro { 131164562Sgshapiro if (Daemons[i].d_socket >= 0) 131264562Sgshapiro (void) close(Daemons[i].d_socket); 131364562Sgshapiro Daemons[i].d_socket = -1; 131464562Sgshapiro } 131538032Speter} 131690792Sgshapiro 131790792Sgshapiro/* 131890792Sgshapiro** GETMODIFIERS -- get modifier flags 131990792Sgshapiro** 132090792Sgshapiro** Parameters: 132190792Sgshapiro** v -- the modifiers (input text line). 132290792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 132390792Sgshapiro** 132490792Sgshapiro** Returns: 132590792Sgshapiro** (xallocat()ed) string representation of modifiers. 132690792Sgshapiro** 132790792Sgshapiro** Side Effects: 132890792Sgshapiro** fills in modifiers. 132990792Sgshapiro*/ 133090792Sgshapiro 133190792Sgshapirochar * 133290792Sgshapirogetmodifiers(v, modifiers) 133390792Sgshapiro char *v; 133490792Sgshapiro BITMAP256 modifiers; 133590792Sgshapiro{ 133690792Sgshapiro int l; 133790792Sgshapiro char *h, *f, *flags; 133890792Sgshapiro 133990792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 134090792Sgshapiro l = 3 * strlen(v) + 3; 134190792Sgshapiro 134290792Sgshapiro /* is someone joking? */ 134390792Sgshapiro if (l < 0 || l > 256) 134490792Sgshapiro { 134590792Sgshapiro if (LogLevel > 2) 134690792Sgshapiro sm_syslog(LOG_ERR, NOQID, 134790792Sgshapiro "getmodifiers too long, ignored"); 134890792Sgshapiro return NULL; 134990792Sgshapiro } 135090792Sgshapiro flags = xalloc(l); 135190792Sgshapiro f = flags; 135290792Sgshapiro clrbitmap(modifiers); 135390792Sgshapiro for (h = v; *h != '\0'; h++) 135490792Sgshapiro { 135590792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 135690792Sgshapiro { 135790792Sgshapiro setbitn(*h, modifiers); 135890792Sgshapiro if (flags != f) 135990792Sgshapiro *flags++ = ' '; 136090792Sgshapiro *flags++ = *h; 136190792Sgshapiro if (isupper(*h)) 136290792Sgshapiro *flags++ = *h; 136390792Sgshapiro } 136490792Sgshapiro } 136590792Sgshapiro *flags++ = '\0'; 136690792Sgshapiro return f; 136790792Sgshapiro} 136890792Sgshapiro 136990792Sgshapiro/* 137090792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 137190792Sgshapiro** 137290792Sgshapiro** Parameters: 137390792Sgshapiro** flag -- the flag to test. 137490792Sgshapiro** 137590792Sgshapiro** Returns: 137690792Sgshapiro** true iff all daemons have set flag. 137790792Sgshapiro*/ 137890792Sgshapiro 137990792Sgshapirobool 138090792Sgshapirochkdaemonmodifiers(flag) 138190792Sgshapiro int flag; 138290792Sgshapiro{ 138390792Sgshapiro int i; 138490792Sgshapiro 138590792Sgshapiro for (i = 0; i < NDaemons; i++) 138690792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 138790792Sgshapiro return false; 138890792Sgshapiro return true; 138990792Sgshapiro} 139090792Sgshapiro 139190792Sgshapiro/* 139264562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 139338032Speter** 139438032Speter** Parameters: 139538032Speter** p -- the options line. 139664562Sgshapiro** d -- the daemon structure to fill in. 139738032Speter** 139838032Speter** Returns: 139938032Speter** none. 140038032Speter*/ 140138032Speter 140264562Sgshapirostatic void 140364562Sgshapirosetsockaddroptions(p, d) 140438032Speter register char *p; 140590792Sgshapiro DAEMON_T *d; 140638032Speter{ 140790792Sgshapiro#if NETISO 140871345Sgshapiro short portno; 140990792Sgshapiro#endif /* NETISO */ 141071345Sgshapiro char *port = NULL; 141171345Sgshapiro char *addr = NULL; 141238032Speter 141390792Sgshapiro#if NETINET 141464562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 141564562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 141690792Sgshapiro#endif /* NETINET */ 141764562Sgshapiro 141838032Speter while (p != NULL) 141938032Speter { 142038032Speter register char *f; 142138032Speter register char *v; 142238032Speter 142338032Speter while (isascii(*p) && isspace(*p)) 142438032Speter p++; 142538032Speter if (*p == '\0') 142638032Speter break; 142738032Speter f = p; 142838032Speter p = strchr(p, ','); 142938032Speter if (p != NULL) 143038032Speter *p++ = '\0'; 143138032Speter v = strchr(f, '='); 143238032Speter if (v == NULL) 143338032Speter continue; 143438032Speter while (isascii(*++v) && isspace(*v)) 143538032Speter continue; 143638032Speter if (isascii(*f) && islower(*f)) 143738032Speter *f = toupper(*f); 143838032Speter 143938032Speter switch (*f) 144038032Speter { 144138032Speter case 'F': /* address family */ 144238032Speter if (isascii(*v) && isdigit(*v)) 144364562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 144490792Sgshapiro#if _FFR_DAEMON_NETUNIX 144590792Sgshapiro# ifdef NETUNIX 144690792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 144790792Sgshapiro sm_strcasecmp(v, "local") == 0) 144890792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 144990792Sgshapiro# endif /* NETUNIX */ 145090792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 145190792Sgshapiro#if NETINET 145290792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 145364562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 145490792Sgshapiro#endif /* NETINET */ 145590792Sgshapiro#if NETINET6 145690792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 145764562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 145890792Sgshapiro#endif /* NETINET6 */ 145990792Sgshapiro#if NETISO 146090792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 146164562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 146290792Sgshapiro#endif /* NETISO */ 146390792Sgshapiro#if NETNS 146490792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 146564562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 146690792Sgshapiro#endif /* NETNS */ 146790792Sgshapiro#if NETX25 146890792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 146964562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 147090792Sgshapiro#endif /* NETX25 */ 147138032Speter else 147264562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 147364562Sgshapiro v); 147438032Speter break; 147538032Speter 147638032Speter case 'A': /* address */ 147771345Sgshapiro addr = v; 147838032Speter break; 147938032Speter 148090792Sgshapiro#if MILTER 148190792Sgshapiro# if _FFR_MILTER_PERDAEMON 148290792Sgshapiro case 'I': 148390792Sgshapiro d->d_inputfilterlist = v; 148490792Sgshapiro break; 148590792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 148690792Sgshapiro#endif /* MILTER */ 148790792Sgshapiro 148838032Speter case 'P': /* port */ 148971345Sgshapiro port = v; 149038032Speter break; 149138032Speter 149238032Speter case 'L': /* listen queue size */ 149364562Sgshapiro d->d_listenqueue = atoi(v); 149438032Speter break; 149538032Speter 149664562Sgshapiro case 'M': /* modifiers (flags) */ 149790792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 149864562Sgshapiro break; 149964562Sgshapiro 150038032Speter case 'S': /* send buffer size */ 150164562Sgshapiro d->d_tcpsndbufsize = atoi(v); 150238032Speter break; 150338032Speter 150438032Speter case 'R': /* receive buffer size */ 150564562Sgshapiro d->d_tcprcvbufsize = atoi(v); 150638032Speter break; 150738032Speter 150864562Sgshapiro case 'N': /* name */ 150964562Sgshapiro d->d_name = v; 151064562Sgshapiro break; 151164562Sgshapiro 151238032Speter default: 151364562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 151464562Sgshapiro f); 151538032Speter } 151638032Speter } 151771345Sgshapiro 151871345Sgshapiro /* Check addr and port after finding family */ 151971345Sgshapiro if (addr != NULL) 152071345Sgshapiro { 152171345Sgshapiro switch (d->d_addr.sa.sa_family) 152271345Sgshapiro { 152390792Sgshapiro#if _FFR_DAEMON_NETUNIX 152490792Sgshapiro# if NETUNIX 152590792Sgshapiro case AF_UNIX: 152690792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 152790792Sgshapiro { 152890792Sgshapiro errno = ENAMETOOLONG; 152990792Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %d", 153090792Sgshapiro addr, sizeof(d->d_addr.sunix.sun_path)); 153190792Sgshapiro break; 153290792Sgshapiro } 153390792Sgshapiro 153490792Sgshapiro /* file safety check done in opendaemonsocket() */ 153590792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 153690792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 153790792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 153890792Sgshapiro addr, 153990792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 154090792Sgshapiro break; 154190792Sgshapiro# endif /* NETUNIX */ 154290792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 154390792Sgshapiro#if NETINET 154471345Sgshapiro case AF_INET: 154571345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 154690792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 154790792Sgshapiro == INADDR_NONE)) 154871345Sgshapiro { 154971345Sgshapiro register struct hostent *hp; 155071345Sgshapiro 155171345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 155271345Sgshapiro if (hp == NULL) 155371345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 155471345Sgshapiro addr); 155571345Sgshapiro else 155671345Sgshapiro { 155771345Sgshapiro while (*(hp->h_addr_list) != NULL && 155871345Sgshapiro hp->h_addrtype != AF_INET) 155971345Sgshapiro hp->h_addr_list++; 156071345Sgshapiro if (*(hp->h_addr_list) == NULL) 156171345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 156271345Sgshapiro addr); 156371345Sgshapiro else 156471345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 156571345Sgshapiro *(hp->h_addr_list), 156671345Sgshapiro INADDRSZ); 156790792Sgshapiro# if NETINET6 156871345Sgshapiro freehostent(hp); 156971345Sgshapiro hp = NULL; 157090792Sgshapiro# endif /* NETINET6 */ 157171345Sgshapiro } 157271345Sgshapiro } 157371345Sgshapiro break; 157490792Sgshapiro#endif /* NETINET */ 157571345Sgshapiro 157690792Sgshapiro#if NETINET6 157771345Sgshapiro case AF_INET6: 157890792Sgshapiro if (anynet_pton(AF_INET6, addr, 157990792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 158071345Sgshapiro { 158171345Sgshapiro register struct hostent *hp; 158271345Sgshapiro 158371345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 158471345Sgshapiro if (hp == NULL) 158571345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 158671345Sgshapiro addr); 158771345Sgshapiro else 158871345Sgshapiro { 158971345Sgshapiro while (*(hp->h_addr_list) != NULL && 159071345Sgshapiro hp->h_addrtype != AF_INET6) 159171345Sgshapiro hp->h_addr_list++; 159271345Sgshapiro if (*(hp->h_addr_list) == NULL) 159371345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 159471345Sgshapiro addr); 159571345Sgshapiro else 159671345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 159771345Sgshapiro *(hp->h_addr_list), 159871345Sgshapiro IN6ADDRSZ); 159971345Sgshapiro freehostent(hp); 160071345Sgshapiro hp = NULL; 160171345Sgshapiro } 160271345Sgshapiro } 160371345Sgshapiro break; 160490792Sgshapiro#endif /* NETINET6 */ 160571345Sgshapiro 160671345Sgshapiro default: 160771345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 160871345Sgshapiro d->d_addr.sa.sa_family); 160971345Sgshapiro break; 161071345Sgshapiro } 161171345Sgshapiro } 161271345Sgshapiro 161371345Sgshapiro if (port != NULL) 161471345Sgshapiro { 161571345Sgshapiro switch (d->d_addr.sa.sa_family) 161671345Sgshapiro { 161790792Sgshapiro#if NETINET 161871345Sgshapiro case AF_INET: 161971345Sgshapiro if (isascii(*port) && isdigit(*port)) 162090792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 162190792Sgshapiro atoi((const char *) port)); 162271345Sgshapiro else 162371345Sgshapiro { 162490792Sgshapiro# ifdef NO_GETSERVBYNAME 162571345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 162671345Sgshapiro port); 162790792Sgshapiro# else /* NO_GETSERVBYNAME */ 162871345Sgshapiro register struct servent *sp; 162971345Sgshapiro 163071345Sgshapiro sp = getservbyname(port, "tcp"); 163171345Sgshapiro if (sp == NULL) 163271345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 163371345Sgshapiro port); 163471345Sgshapiro else 163571345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 163690792Sgshapiro# endif /* NO_GETSERVBYNAME */ 163771345Sgshapiro } 163871345Sgshapiro break; 163990792Sgshapiro#endif /* NETINET */ 164071345Sgshapiro 164190792Sgshapiro#if NETINET6 164271345Sgshapiro case AF_INET6: 164371345Sgshapiro if (isascii(*port) && isdigit(*port)) 164490792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 164590792Sgshapiro atoi(port)); 164671345Sgshapiro else 164771345Sgshapiro { 164890792Sgshapiro# ifdef NO_GETSERVBYNAME 164971345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 165071345Sgshapiro port); 165190792Sgshapiro# else /* NO_GETSERVBYNAME */ 165271345Sgshapiro register struct servent *sp; 165371345Sgshapiro 165471345Sgshapiro sp = getservbyname(port, "tcp"); 165571345Sgshapiro if (sp == NULL) 165671345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 165771345Sgshapiro port); 165871345Sgshapiro else 165971345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 166090792Sgshapiro# endif /* NO_GETSERVBYNAME */ 166171345Sgshapiro } 166271345Sgshapiro break; 166390792Sgshapiro#endif /* NETINET6 */ 166471345Sgshapiro 166590792Sgshapiro#if NETISO 166671345Sgshapiro case AF_ISO: 166771345Sgshapiro /* assume two byte transport selector */ 166871345Sgshapiro if (isascii(*port) && isdigit(*port)) 166990792Sgshapiro portno = htons((unsigned short) atoi(port)); 167071345Sgshapiro else 167171345Sgshapiro { 167290792Sgshapiro# ifdef NO_GETSERVBYNAME 167371345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 167471345Sgshapiro port); 167590792Sgshapiro# else /* NO_GETSERVBYNAME */ 167671345Sgshapiro register struct servent *sp; 167771345Sgshapiro 167871345Sgshapiro sp = getservbyname(port, "tcp"); 167971345Sgshapiro if (sp == NULL) 168071345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 168171345Sgshapiro port); 168271345Sgshapiro else 168371345Sgshapiro portno = sp->s_port; 168490792Sgshapiro# endif /* NO_GETSERVBYNAME */ 168571345Sgshapiro } 168671345Sgshapiro memmove(TSEL(&d->d_addr.siso), 168771345Sgshapiro (char *) &portno, 2); 168871345Sgshapiro break; 168990792Sgshapiro#endif /* NETISO */ 169071345Sgshapiro 169171345Sgshapiro default: 169271345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 169371345Sgshapiro d->d_addr.sa.sa_family); 169471345Sgshapiro break; 169571345Sgshapiro } 169671345Sgshapiro } 169738032Speter} 169890792Sgshapiro/* 169964562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 170038032Speter** 170138032Speter** Parameters: 170264562Sgshapiro** p -- the options line. 170364562Sgshapiro** 170464562Sgshapiro** Returns: 170590792Sgshapiro** true if successful, false otherwise. 170690792Sgshapiro** 170790792Sgshapiro** Side Effects: 170890792Sgshapiro** increments number of daemons. 170964562Sgshapiro*/ 171064562Sgshapiro 171190792Sgshapiro#define DEF_LISTENQUEUE 10 171290792Sgshapiro 171364562Sgshapirobool 171464562Sgshapirosetdaemonoptions(p) 171564562Sgshapiro register char *p; 171664562Sgshapiro{ 171790792Sgshapiro if (NDaemons >= MAXDAEMONS) 171890792Sgshapiro return false; 171990792Sgshapiro Daemons[NDaemons].d_socket = -1; 172090792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 172190792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 172290792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 172364562Sgshapiro 172490792Sgshapiro#if MILTER 172590792Sgshapiro# if _FFR_MILTER_PERDAEMON 172690792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 172790792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 172890792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 172990792Sgshapiro#endif /* MILTER */ 173090792Sgshapiro 173190792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 173290792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 173364562Sgshapiro else 173464562Sgshapiro { 173564562Sgshapiro char num[30]; 173664562Sgshapiro 173790792Sgshapiro (void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons); 173890792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 173964562Sgshapiro } 174064562Sgshapiro 174164562Sgshapiro if (tTd(37, 1)) 174264562Sgshapiro { 174390792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 174490792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[NDaemons].d_flags)) 174590792Sgshapiro sm_dprintf("ETRNONLY "); 174690792Sgshapiro if (bitnset(D_NOETRN, Daemons[NDaemons].d_flags)) 174790792Sgshapiro sm_dprintf("NOETRN "); 174890792Sgshapiro sm_dprintf("\n"); 174964562Sgshapiro } 175090792Sgshapiro ++NDaemons; 175190792Sgshapiro return true; 175264562Sgshapiro} 175390792Sgshapiro/* 175464562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 175564562Sgshapiro** 175664562Sgshapiro** Parameters: 175764562Sgshapiro** none 175864562Sgshapiro** 175964562Sgshapiro** Returns: 176064562Sgshapiro** none 176164562Sgshapiro** 176264562Sgshapiro** Side Effects: 176364562Sgshapiro** initializes structure for one daemon. 176464562Sgshapiro*/ 176590792Sgshapiro 176664562Sgshapirovoid 176764562Sgshapiroinitdaemon() 176864562Sgshapiro{ 176990792Sgshapiro if (NDaemons == 0) 177064562Sgshapiro { 177190792Sgshapiro Daemons[NDaemons].d_socket = -1; 177290792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 177390792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 177490792Sgshapiro NDaemons = 1; 177564562Sgshapiro } 177664562Sgshapiro} 177790792Sgshapiro/* 177864562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 177964562Sgshapiro** 178064562Sgshapiro** Parameters: 178164562Sgshapiro** p -- the options line. 178264562Sgshapiro** 178364562Sgshapiro** Returns: 178464562Sgshapiro** none. 178564562Sgshapiro*/ 178664562Sgshapiro 178790792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 178864562Sgshapiro 178964562Sgshapirovoid 179064562Sgshapirosetclientoptions(p) 179164562Sgshapiro register char *p; 179264562Sgshapiro{ 179390792Sgshapiro int family; 179490792Sgshapiro DAEMON_T d; 179564562Sgshapiro 179664562Sgshapiro memset(&d, '\0', sizeof d); 179764562Sgshapiro setsockaddroptions(p, &d); 179864562Sgshapiro 179964562Sgshapiro /* grab what we need */ 180090792Sgshapiro family = d.d_addr.sa.sa_family; 180190792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 180290792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 180390792Sgshapiro if (d.d_name != NULL) 180490792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 180564562Sgshapiro else 180690792Sgshapiro { 180790792Sgshapiro char num[30]; 180890792Sgshapiro 180990792Sgshapiro (void) sm_snprintf(num, sizeof num, "Client%d", family); 181090792Sgshapiro ClientSettings[family].d_name = newstr(num); 181190792Sgshapiro } 181264562Sgshapiro} 181390792Sgshapiro/* 181464562Sgshapiro** ADDR_FAMILY -- determine address family from address 181564562Sgshapiro** 181664562Sgshapiro** Parameters: 181764562Sgshapiro** addr -- the string representation of the address 181864562Sgshapiro** 181964562Sgshapiro** Returns: 182064562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 182164562Sgshapiro** 182264562Sgshapiro** Side Effects: 182364562Sgshapiro** none. 182464562Sgshapiro*/ 182564562Sgshapiro 182664562Sgshapirostatic int 182764562Sgshapiroaddr_family(addr) 182864562Sgshapiro char *addr; 182964562Sgshapiro{ 183090792Sgshapiro#if NETINET6 183164562Sgshapiro SOCKADDR clt_addr; 183290792Sgshapiro#endif /* NETINET6 */ 183364562Sgshapiro 183490792Sgshapiro#if NETINET 183564562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 183664562Sgshapiro { 183764562Sgshapiro if (tTd(16, 9)) 183890792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 183964562Sgshapiro return AF_INET; 184064562Sgshapiro } 184190792Sgshapiro#endif /* NETINET */ 184290792Sgshapiro#if NETINET6 184390792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 184464562Sgshapiro { 184564562Sgshapiro if (tTd(16, 9)) 184690792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 184764562Sgshapiro return AF_INET6; 184864562Sgshapiro } 184990792Sgshapiro#endif /* NETINET6 */ 185090792Sgshapiro#if _FFR_DAEMON_NETUNIX 185190792Sgshapiro# if NETUNIX 185290792Sgshapiro if (*addr == '/') 185390792Sgshapiro { 185490792Sgshapiro if (tTd(16, 9)) 185590792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 185690792Sgshapiro return AF_UNIX; 185790792Sgshapiro } 185890792Sgshapiro# endif /* NETUNIX */ 185990792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 186064562Sgshapiro if (tTd(16, 9)) 186190792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 186264562Sgshapiro return AF_UNSPEC; 186364562Sgshapiro} 186490792Sgshapiro 186590792Sgshapiro/* 186690792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 186790792Sgshapiro** 186890792Sgshapiro** Parameters: 186990792Sgshapiro** flag -- the flag to test. 187090792Sgshapiro** 187190792Sgshapiro** Returns: 187290792Sgshapiro** true iff all configured clients have set the flag. 187390792Sgshapiro*/ 187490792Sgshapiro 187590792Sgshapirobool 187690792Sgshapirochkclientmodifiers(flag) 187790792Sgshapiro int flag; 187890792Sgshapiro{ 187990792Sgshapiro int i; 188090792Sgshapiro bool flagisset; 188190792Sgshapiro 188290792Sgshapiro flagisset = false; 188390792Sgshapiro for (i = 0; i < AF_MAX; i++) 188490792Sgshapiro { 188590792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 188690792Sgshapiro { 188790792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 188890792Sgshapiro return false; 188990792Sgshapiro flagisset = true; 189090792Sgshapiro } 189190792Sgshapiro } 189290792Sgshapiro return flagisset; 189390792Sgshapiro} 189490792Sgshapiro 189590792Sgshapiro#if MILTER 189690792Sgshapiro# if _FFR_MILTER_PERDAEMON 189790792Sgshapiro/* 189890792Sgshapiro** SETUP_DAEMON_FILTERS -- Parse per-socket filters 189990792Sgshapiro** 190090792Sgshapiro** Parameters: 190190792Sgshapiro** none 190290792Sgshapiro** 190390792Sgshapiro** Returns: 190490792Sgshapiro** none 190590792Sgshapiro*/ 190690792Sgshapiro 190790792Sgshapirovoid 190890792Sgshapirosetup_daemon_milters() 190990792Sgshapiro{ 191090792Sgshapiro int idx; 191190792Sgshapiro 191290792Sgshapiro if (OpMode == MD_SMTP) 191390792Sgshapiro { 191490792Sgshapiro /* no need to configure the daemons */ 191590792Sgshapiro return; 191690792Sgshapiro } 191790792Sgshapiro 191890792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 191990792Sgshapiro { 192090792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 192190792Sgshapiro { 192290792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 192390792Sgshapiro Daemons[idx].d_inputfilters, 192490792Sgshapiro MAXFILTERS); 192590792Sgshapiro } 192690792Sgshapiro } 192790792Sgshapiro} 192890792Sgshapiro# endif /* _FFR_MILTER_PERDAEMON */ 192990792Sgshapiro#endif /* MILTER */ 193090792Sgshapiro/* 193164562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 193264562Sgshapiro** 193364562Sgshapiro** Parameters: 193438032Speter** host -- the name of the host. 193538032Speter** port -- the port number to connect to. 193638032Speter** mci -- a pointer to the mail connection information 193738032Speter** structure to be filled in. 193838032Speter** e -- the current envelope. 193990792Sgshapiro** enough -- time at which to stop further connection attempts. 194090792Sgshapiro** (0 means no limit) 194138032Speter** 194238032Speter** Returns: 194338032Speter** An exit code telling whether the connection could be 194438032Speter** made and if not why not. 194538032Speter** 194638032Speter** Side Effects: 194738032Speter** none. 194838032Speter*/ 194938032Speter 195038032Speterstatic jmp_buf CtxConnectTimeout; 195138032Speter 195238032SpeterSOCKADDR CurHostAddr; /* address of current host */ 195338032Speter 195438032Speterint 195590792Sgshapiromakeconnection(host, port, mci, e, enough) 195638032Speter char *host; 195790792Sgshapiro volatile unsigned int port; 195838032Speter register MCI *mci; 195938032Speter ENVELOPE *e; 196090792Sgshapiro time_t enough; 196138032Speter{ 196238032Speter register volatile int addrno = 0; 196390792Sgshapiro volatile int s; 196490792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 196538032Speter SOCKADDR addr; 196664562Sgshapiro SOCKADDR clt_addr; 196764562Sgshapiro int save_errno = 0; 196864562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 196938032Speter volatile bool firstconnect; 197090792Sgshapiro SM_EVENT *volatile ev = NULL; 197190792Sgshapiro#if NETINET6 197290792Sgshapiro volatile bool v6found = false; 197390792Sgshapiro#endif /* NETINET6 */ 197464562Sgshapiro volatile int family = InetMode; 197564562Sgshapiro SOCKADDR_LEN_T len; 197664562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 197764562Sgshapiro volatile bool clt_bind; 197864562Sgshapiro BITMAP256 d_flags; 197964562Sgshapiro char *p; 198064562Sgshapiro extern ENVELOPE BlankEnvelope; 198138032Speter 198290792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 198364562Sgshapiro clrbitmap(d_flags); 198490792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 198564562Sgshapiro { 198664562Sgshapiro for (; *p != '\0'; p++) 198764562Sgshapiro { 198864562Sgshapiro if (!(isascii(*p) && isspace(*p))) 198971345Sgshapiro setbitn(bitidx(*p), d_flags); 199064562Sgshapiro } 199164562Sgshapiro } 199264562Sgshapiro 199390792Sgshapiro#if NETINET6 199464562Sgshapiro v4retry: 199590792Sgshapiro#endif /* NETINET6 */ 199690792Sgshapiro clt_bind = false; 199764562Sgshapiro 199864562Sgshapiro /* Set up the address for outgoing connection. */ 199964562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 200090792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 200173188Sgshapiro *p != '\0') 200264562Sgshapiro { 200390792Sgshapiro#if NETINET6 200464562Sgshapiro char p6[INET6_ADDRSTRLEN]; 200590792Sgshapiro#endif /* NETINET6 */ 200664562Sgshapiro 200764562Sgshapiro memset(&clt_addr, '\0', sizeof clt_addr); 200864562Sgshapiro 200964562Sgshapiro /* infer the address family from the address itself */ 201064562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 201164562Sgshapiro switch (clt_addr.sa.sa_family) 201264562Sgshapiro { 201390792Sgshapiro#if NETINET 201464562Sgshapiro case AF_INET: 201573188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 201673188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 201773188Sgshapiro clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK) 201864562Sgshapiro { 201990792Sgshapiro clt_bind = true; 202064562Sgshapiro socksize = sizeof (struct sockaddr_in); 202164562Sgshapiro } 202264562Sgshapiro break; 202390792Sgshapiro#endif /* NETINET */ 202464562Sgshapiro 202590792Sgshapiro#if NETINET6 202664562Sgshapiro case AF_INET6: 202764562Sgshapiro if (inet_addr(p) != INADDR_NONE) 202890792Sgshapiro (void) sm_snprintf(p6, sizeof p6, 202990792Sgshapiro "IPv6:::ffff:%s", p); 203064562Sgshapiro else 203190792Sgshapiro (void) sm_strlcpy(p6, p, sizeof p6); 203290792Sgshapiro if (anynet_pton(AF_INET6, p6, 203390792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 203473188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 203564562Sgshapiro { 203690792Sgshapiro clt_bind = true; 203764562Sgshapiro socksize = sizeof (struct sockaddr_in6); 203864562Sgshapiro } 203964562Sgshapiro break; 204090792Sgshapiro#endif /* NETINET6 */ 204164562Sgshapiro 204290792Sgshapiro#if 0 204364562Sgshapiro default: 204464562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 204564562Sgshapiro clt_addr.sa.sa_family); 204664562Sgshapiro break; 204790792Sgshapiro#endif /* 0 */ 204864562Sgshapiro } 204964562Sgshapiro if (clt_bind) 205064562Sgshapiro family = clt_addr.sa.sa_family; 205164562Sgshapiro } 205290792Sgshapiro 205390792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 205490792Sgshapiro if (!clt_bind) 205564562Sgshapiro { 205690792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 205764562Sgshapiro switch (clt_addr.sa.sa_family) 205864562Sgshapiro { 205990792Sgshapiro#if NETINET 206064562Sgshapiro case AF_INET: 206164562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 206264562Sgshapiro clt_addr.sin.sin_addr.s_addr = INADDR_ANY; 206364562Sgshapiro else 206490792Sgshapiro clt_bind = true; 206564562Sgshapiro if (clt_addr.sin.sin_port != 0) 206690792Sgshapiro clt_bind = true; 206764562Sgshapiro socksize = sizeof (struct sockaddr_in); 206864562Sgshapiro break; 206990792Sgshapiro#endif /* NETINET */ 207090792Sgshapiro#if NETINET6 207164562Sgshapiro case AF_INET6: 207264562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 207364562Sgshapiro clt_addr.sin6.sin6_addr = in6addr_any; 207464562Sgshapiro else 207590792Sgshapiro clt_bind = true; 207664562Sgshapiro socksize = sizeof (struct sockaddr_in6); 207764562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 207890792Sgshapiro clt_bind = true; 207964562Sgshapiro break; 208090792Sgshapiro#endif /* NETINET6 */ 208190792Sgshapiro#if NETISO 208264562Sgshapiro case AF_ISO: 208364562Sgshapiro socksize = sizeof clt_addr.siso; 208490792Sgshapiro clt_bind = true; 208564562Sgshapiro break; 208690792Sgshapiro#endif /* NETISO */ 208764562Sgshapiro default: 208864562Sgshapiro break; 208964562Sgshapiro } 209064562Sgshapiro } 209164562Sgshapiro 209238032Speter /* 209338032Speter ** Set up the address for the mailer. 209438032Speter ** Accept "[a.b.c.d]" syntax for host name. 209538032Speter */ 209638032Speter 209773188Sgshapiro SM_SET_H_ERRNO(0); 209838032Speter errno = 0; 209964562Sgshapiro memset(&CurHostAddr, '\0', sizeof CurHostAddr); 210064562Sgshapiro memset(&addr, '\0', sizeof addr); 210138032Speter SmtpPhase = mci->mci_phase = "initial connection"; 210238032Speter CurHostName = host; 210338032Speter 210438032Speter if (host[0] == '[') 210538032Speter { 210664562Sgshapiro p = strchr(host, ']'); 210738032Speter if (p != NULL) 210838032Speter { 210990792Sgshapiro#if NETINET 211064562Sgshapiro unsigned long hid = INADDR_NONE; 211190792Sgshapiro#endif /* NETINET */ 211290792Sgshapiro#if NETINET6 211364562Sgshapiro struct sockaddr_in6 hid6; 211490792Sgshapiro#endif /* NETINET6 */ 211564562Sgshapiro 211638032Speter *p = '\0'; 211790792Sgshapiro#if NETINET6 211864562Sgshapiro memset(&hid6, '\0', sizeof hid6); 211990792Sgshapiro#endif /* NETINET6 */ 212090792Sgshapiro#if NETINET 212164562Sgshapiro if (family == AF_INET && 212264562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 212338032Speter { 212464562Sgshapiro addr.sin.sin_family = AF_INET; 212564562Sgshapiro addr.sin.sin_addr.s_addr = hid; 212664562Sgshapiro } 212764562Sgshapiro else 212890792Sgshapiro#endif /* NETINET */ 212990792Sgshapiro#if NETINET6 213064562Sgshapiro if (family == AF_INET6 && 213190792Sgshapiro anynet_pton(AF_INET6, &host[1], 213290792Sgshapiro &hid6.sin6_addr) == 1) 213364562Sgshapiro { 213464562Sgshapiro addr.sin6.sin6_family = AF_INET6; 213564562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 213664562Sgshapiro } 213764562Sgshapiro else 213890792Sgshapiro#endif /* NETINET6 */ 213964562Sgshapiro { 214038032Speter /* try it as a host name (avoid MX lookup) */ 214164562Sgshapiro hp = sm_gethostbyname(&host[1], family); 214238032Speter if (hp == NULL && p[-1] == '.') 214338032Speter { 214490792Sgshapiro#if NAMED_BIND 214538032Speter int oldopts = _res.options; 214638032Speter 214738032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 214890792Sgshapiro#endif /* NAMED_BIND */ 214938032Speter p[-1] = '\0'; 215064562Sgshapiro hp = sm_gethostbyname(&host[1], 215164562Sgshapiro family); 215238032Speter p[-1] = '.'; 215390792Sgshapiro#if NAMED_BIND 215438032Speter _res.options = oldopts; 215590792Sgshapiro#endif /* NAMED_BIND */ 215638032Speter } 215738032Speter *p = ']'; 215838032Speter goto gothostent; 215938032Speter } 216038032Speter *p = ']'; 216138032Speter } 216238032Speter if (p == NULL) 216338032Speter { 216438032Speter extern char MsgBuf[]; 216538032Speter 216664562Sgshapiro usrerrenh("5.1.2", 216764562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 216864562Sgshapiro host); 216938032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 217064562Sgshapiro errno = EINVAL; 217138032Speter return EX_NOHOST; 217238032Speter } 217338032Speter } 217438032Speter else 217538032Speter { 217638032Speter /* contortion to get around SGI cc complaints */ 217738032Speter { 217864562Sgshapiro p = &host[strlen(host) - 1]; 217964562Sgshapiro hp = sm_gethostbyname(host, family); 218038032Speter if (hp == NULL && *p == '.') 218138032Speter { 218290792Sgshapiro#if NAMED_BIND 218338032Speter int oldopts = _res.options; 218438032Speter 218538032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 218690792Sgshapiro#endif /* NAMED_BIND */ 218738032Speter *p = '\0'; 218864562Sgshapiro hp = sm_gethostbyname(host, family); 218938032Speter *p = '.'; 219090792Sgshapiro#if NAMED_BIND 219138032Speter _res.options = oldopts; 219290792Sgshapiro#endif /* NAMED_BIND */ 219338032Speter } 219438032Speter } 219538032Spetergothostent: 219638032Speter if (hp == NULL) 219738032Speter { 219890792Sgshapiro#if NAMED_BIND 219938032Speter /* check for name server timeouts */ 220090792Sgshapiro# if NETINET6 220190792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 220290792Sgshapiro errno == ETIMEDOUT) 220338032Speter { 220490792Sgshapiro /* 220590792Sgshapiro ** An attempt with family AF_INET may 220690792Sgshapiro ** succeed By skipping the next section 220790792Sgshapiro ** of code, we will try AF_INET before 220890792Sgshapiro ** failing. 220990792Sgshapiro */ 221090792Sgshapiro 221190792Sgshapiro if (tTd(16, 10)) 221290792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 221338032Speter } 221490792Sgshapiro else 221590792Sgshapiro# endif /* NETINET6 */ 221690792Sgshapiro { 221790792Sgshapiro if (errno == ETIMEDOUT || 221890792Sgshapiro h_errno == TRY_AGAIN || 221990792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 222090792Sgshapiro { 222190792Sgshapiro save_errno = errno; 222290792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 222390792Sgshapiro "4.4.3", NULL); 222490792Sgshapiro errno = save_errno; 222590792Sgshapiro return EX_TEMPFAIL; 222690792Sgshapiro } 222790792Sgshapiro } 222890792Sgshapiro#endif /* NAMED_BIND */ 222990792Sgshapiro#if NETINET6 223064562Sgshapiro /* 223164562Sgshapiro ** Try v6 first, then fall back to v4. 223264562Sgshapiro ** If we found a v6 address, but no v4 223364562Sgshapiro ** addresses, then TEMPFAIL. 223464562Sgshapiro */ 223564562Sgshapiro 223664562Sgshapiro if (family == AF_INET6) 223764562Sgshapiro { 223864562Sgshapiro family = AF_INET; 223964562Sgshapiro goto v4retry; 224064562Sgshapiro } 224164562Sgshapiro if (v6found) 224264562Sgshapiro goto v6tempfail; 224390792Sgshapiro#endif /* NETINET6 */ 224464562Sgshapiro save_errno = errno; 224538032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 224664562Sgshapiro errno = save_errno; 224764562Sgshapiro return EX_NOHOST; 224838032Speter } 224938032Speter addr.sa.sa_family = hp->h_addrtype; 225038032Speter switch (hp->h_addrtype) 225138032Speter { 225290792Sgshapiro#if NETINET 225338032Speter case AF_INET: 225464562Sgshapiro memmove(&addr.sin.sin_addr, 225564562Sgshapiro hp->h_addr, 225638032Speter INADDRSZ); 225738032Speter break; 225890792Sgshapiro#endif /* NETINET */ 225938032Speter 226090792Sgshapiro#if NETINET6 226164562Sgshapiro case AF_INET6: 226264562Sgshapiro memmove(&addr.sin6.sin6_addr, 226364562Sgshapiro hp->h_addr, 226464562Sgshapiro IN6ADDRSZ); 226564562Sgshapiro break; 226690792Sgshapiro#endif /* NETINET6 */ 226764562Sgshapiro 226838032Speter default: 226938032Speter if (hp->h_length > sizeof addr.sa.sa_data) 227038032Speter { 227138032Speter syserr("makeconnection: long sa_data: family %d len %d", 227238032Speter hp->h_addrtype, hp->h_length); 227338032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 227464562Sgshapiro errno = EINVAL; 227538032Speter return EX_NOHOST; 227638032Speter } 227790792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 227838032Speter break; 227938032Speter } 228038032Speter addrno = 1; 228138032Speter } 228238032Speter 228338032Speter /* 228438032Speter ** Determine the port number. 228538032Speter */ 228638032Speter 228738032Speter if (port == 0) 228838032Speter { 228990792Sgshapiro#ifdef NO_GETSERVBYNAME 229064562Sgshapiro port = htons(25); 229190792Sgshapiro#else /* NO_GETSERVBYNAME */ 229238032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 229338032Speter 229438032Speter if (sp == NULL) 229538032Speter { 229638032Speter if (LogLevel > 2) 229738032Speter sm_syslog(LOG_ERR, NOQID, 229864562Sgshapiro "makeconnection: service \"smtp\" unknown"); 229938032Speter port = htons(25); 230038032Speter } 230138032Speter else 230238032Speter port = sp->s_port; 230390792Sgshapiro#endif /* NO_GETSERVBYNAME */ 230438032Speter } 230538032Speter 230690792Sgshapiro#if NETINET6 230790792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 230890792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 230990792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 231090792Sgshapiro { 231190792Sgshapiro /* 231290792Sgshapiro ** Ignore mapped IPv4 address since 231390792Sgshapiro ** there is a ClientPortOptions setting 231490792Sgshapiro ** for IPv4. 231590792Sgshapiro */ 231690792Sgshapiro 231790792Sgshapiro goto nextaddr; 231890792Sgshapiro } 231990792Sgshapiro#endif /* NETINET6 */ 232090792Sgshapiro 232138032Speter switch (addr.sa.sa_family) 232238032Speter { 232390792Sgshapiro#if NETINET 232438032Speter case AF_INET: 232538032Speter addr.sin.sin_port = port; 232638032Speter addrlen = sizeof (struct sockaddr_in); 232738032Speter break; 232890792Sgshapiro#endif /* NETINET */ 232938032Speter 233090792Sgshapiro#if NETINET6 233164562Sgshapiro case AF_INET6: 233264562Sgshapiro addr.sin6.sin6_port = port; 233364562Sgshapiro addrlen = sizeof (struct sockaddr_in6); 233464562Sgshapiro break; 233590792Sgshapiro#endif /* NETINET6 */ 233664562Sgshapiro 233790792Sgshapiro#if NETISO 233838032Speter case AF_ISO: 233938032Speter /* assume two byte transport selector */ 234064562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 234138032Speter addrlen = sizeof (struct sockaddr_iso); 234238032Speter break; 234390792Sgshapiro#endif /* NETISO */ 234438032Speter 234538032Speter default: 234638032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 234738032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 234864562Sgshapiro errno = EINVAL; 234990792Sgshapiro#if NETINET6 235071345Sgshapiro if (hp != NULL) 235171345Sgshapiro freehostent(hp); 235290792Sgshapiro#endif /* NETINET6 */ 235364562Sgshapiro return EX_NOHOST; 235438032Speter } 235538032Speter 235638032Speter /* 235738032Speter ** Try to actually open the connection. 235838032Speter */ 235938032Speter 236090792Sgshapiro#if XLA 236138032Speter /* if too many connections, don't bother trying */ 236238032Speter if (!xla_noqueue_ok(host)) 236371345Sgshapiro { 236490792Sgshapiro# if NETINET6 236571345Sgshapiro if (hp != NULL) 236671345Sgshapiro freehostent(hp); 236790792Sgshapiro# endif /* NETINET6 */ 236838032Speter return EX_TEMPFAIL; 236971345Sgshapiro } 237090792Sgshapiro#endif /* XLA */ 237138032Speter 237290792Sgshapiro firstconnect = true; 237338032Speter for (;;) 237438032Speter { 237538032Speter if (tTd(16, 1)) 237690792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 237790792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 237890792Sgshapiro (int) addr.sa.sa_family); 237938032Speter 238038032Speter /* save for logging */ 238138032Speter CurHostAddr = addr; 238238032Speter 238390792Sgshapiro#if HASRRESVPORT 238438032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 238538032Speter { 238638032Speter int rport = IPPORT_RESERVED - 1; 238738032Speter 238838032Speter s = rresvport(&rport); 238938032Speter } 239038032Speter else 239190792Sgshapiro#endif /* HASRRESVPORT */ 239238032Speter { 239390792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 239438032Speter } 239538032Speter if (s < 0) 239638032Speter { 239764562Sgshapiro save_errno = errno; 239838032Speter syserr("makeconnection: cannot create socket"); 239990792Sgshapiro#if XLA 240038032Speter xla_host_end(host); 240190792Sgshapiro#endif /* XLA */ 240238032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 240390792Sgshapiro#if NETINET6 240471345Sgshapiro if (hp != NULL) 240571345Sgshapiro freehostent(hp); 240690792Sgshapiro#endif /* NETINET6 */ 240764562Sgshapiro errno = save_errno; 240838032Speter return EX_TEMPFAIL; 240938032Speter } 241038032Speter 241190792Sgshapiro#ifdef SO_SNDBUF 241290792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 241338032Speter { 241438032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 241590792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 241690792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 241738032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 241838032Speter } 241990792Sgshapiro#endif /* SO_SNDBUF */ 242090792Sgshapiro#ifdef SO_RCVBUF 242190792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 242264562Sgshapiro { 242364562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 242490792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 242590792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 242664562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 242764562Sgshapiro } 242890792Sgshapiro#endif /* SO_RCVBUF */ 242938032Speter 243038032Speter if (tTd(16, 1)) 243190792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 243238032Speter 243338032Speter /* turn on network debugging? */ 243438032Speter if (tTd(16, 101)) 243538032Speter { 243638032Speter int on = 1; 243764562Sgshapiro 243838032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 243938032Speter (char *)&on, sizeof on); 244038032Speter } 244190792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 244290792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 244390792Sgshapiro errno = 0; /* for debugging */ 244438032Speter 244564562Sgshapiro if (clt_bind) 244664562Sgshapiro { 244764562Sgshapiro int on = 1; 244864562Sgshapiro 244964562Sgshapiro switch (clt_addr.sa.sa_family) 245064562Sgshapiro { 245190792Sgshapiro#if NETINET 245264562Sgshapiro case AF_INET: 245364562Sgshapiro if (clt_addr.sin.sin_port != 0) 245464562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 245564562Sgshapiro SO_REUSEADDR, 245664562Sgshapiro (char *) &on, 245764562Sgshapiro sizeof on); 245864562Sgshapiro break; 245990792Sgshapiro#endif /* NETINET */ 246064562Sgshapiro 246190792Sgshapiro#if NETINET6 246264562Sgshapiro case AF_INET6: 246364562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 246464562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 246564562Sgshapiro SO_REUSEADDR, 246664562Sgshapiro (char *) &on, 246764562Sgshapiro sizeof on); 246864562Sgshapiro break; 246990792Sgshapiro#endif /* NETINET6 */ 247064562Sgshapiro } 247164562Sgshapiro 247264562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 247364562Sgshapiro { 247464562Sgshapiro save_errno = errno; 247564562Sgshapiro (void) close(s); 247664562Sgshapiro errno = save_errno; 247764562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 247864562Sgshapiro anynet_ntoa(&clt_addr)); 247990792Sgshapiro#if NETINET6 248071345Sgshapiro if (hp != NULL) 248171345Sgshapiro freehostent(hp); 248290792Sgshapiro#endif /* NETINET6 */ 248364562Sgshapiro errno = save_errno; 248464562Sgshapiro return EX_TEMPFAIL; 248564562Sgshapiro } 248664562Sgshapiro } 248764562Sgshapiro 248838032Speter /* 248938032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 249038032Speter ** Time out the connect to avoid this problem. 249138032Speter */ 249238032Speter 249338032Speter if (setjmp(CtxConnectTimeout) == 0) 249438032Speter { 249538032Speter int i; 249638032Speter 249738032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 249890792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 249990792Sgshapiro connecttimeout, 0); 250038032Speter else if (TimeOuts.to_connect != 0) 250190792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 250290792Sgshapiro connecttimeout, 0); 250338032Speter else 250438032Speter ev = NULL; 250538032Speter 250664562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 250764562Sgshapiro { 250890792Sgshapiro#if NETINET 250964562Sgshapiro case AF_INET: 251064562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 251164562Sgshapiro break; 251290792Sgshapiro#endif /* NETINET */ 251364562Sgshapiro 251490792Sgshapiro#if NETINET6 251564562Sgshapiro case AF_INET6: 251664562Sgshapiro memmove(&addr.sin6.sin6_addr, 251764562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 251864562Sgshapiro IN6ADDRSZ); 251964562Sgshapiro break; 252090792Sgshapiro#endif /* NETINET6 */ 252164562Sgshapiro } 252238032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 252364562Sgshapiro save_errno = errno; 252438032Speter if (ev != NULL) 252590792Sgshapiro sm_clrevent(ev); 252638032Speter if (i >= 0) 252738032Speter break; 252838032Speter } 252938032Speter else 253064562Sgshapiro save_errno = errno; 253138032Speter 253294334Sgshapiro /* couldn't connect.... figure out why */ 253394334Sgshapiro (void) close(s); 253494334Sgshapiro 253538032Speter /* if running demand-dialed connection, try again */ 253690792Sgshapiro if (DialDelay > 0 && firstconnect && 253790792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 253838032Speter { 253938032Speter if (tTd(16, 1)) 254090792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 254190792Sgshapiro sm_errstring(save_errno)); 254290792Sgshapiro firstconnect = false; 254364562Sgshapiro (void) sleep(DialDelay); 254438032Speter continue; 254538032Speter } 254638032Speter 254790792Sgshapiro if (LogLevel > 13) 254838032Speter sm_syslog(LOG_INFO, e->e_id, 254938032Speter "makeconnection (%s [%s]) failed: %s", 255038032Speter host, anynet_ntoa(&addr), 255190792Sgshapiro sm_errstring(save_errno)); 255238032Speter 255390792Sgshapiro#if NETINET6 255490792Sgshapironextaddr: 255590792Sgshapiro#endif /* NETINET6 */ 255690792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 255790792Sgshapiro (enough == 0 || curtime() < enough)) 255838032Speter { 255938032Speter if (tTd(16, 1)) 256090792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 256190792Sgshapiro sm_errstring(save_errno)); 256238032Speter switch (addr.sa.sa_family) 256338032Speter { 256490792Sgshapiro#if NETINET 256538032Speter case AF_INET: 256664562Sgshapiro memmove(&addr.sin.sin_addr, 256764562Sgshapiro hp->h_addr_list[addrno++], 256864562Sgshapiro INADDRSZ); 256938032Speter break; 257090792Sgshapiro#endif /* NETINET */ 257138032Speter 257290792Sgshapiro#if NETINET6 257364562Sgshapiro case AF_INET6: 257464562Sgshapiro memmove(&addr.sin6.sin6_addr, 257564562Sgshapiro hp->h_addr_list[addrno++], 257664562Sgshapiro IN6ADDRSZ); 257764562Sgshapiro break; 257890792Sgshapiro#endif /* NETINET6 */ 257964562Sgshapiro 258038032Speter default: 258164562Sgshapiro memmove(addr.sa.sa_data, 258264562Sgshapiro hp->h_addr_list[addrno++], 258338032Speter hp->h_length); 258438032Speter break; 258538032Speter } 258638032Speter continue; 258738032Speter } 258864562Sgshapiro errno = save_errno; 258938032Speter 259090792Sgshapiro#if NETINET6 259164562Sgshapiro if (family == AF_INET6) 259264562Sgshapiro { 259364562Sgshapiro if (tTd(16, 1)) 259490792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 259590792Sgshapiro sm_errstring(save_errno)); 259690792Sgshapiro v6found = true; 259764562Sgshapiro family = AF_INET; 259871345Sgshapiro if (hp != NULL) 259971345Sgshapiro { 260071345Sgshapiro freehostent(hp); 260171345Sgshapiro hp = NULL; 260271345Sgshapiro } 260364562Sgshapiro goto v4retry; 260464562Sgshapiro } 260564562Sgshapiro v6tempfail: 260690792Sgshapiro#endif /* NETINET6 */ 260738032Speter /* couldn't open connection */ 260890792Sgshapiro#if NETINET6 260964562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 261064562Sgshapiro if (errno > 0) 261190792Sgshapiro#endif /* NETINET6 */ 261264562Sgshapiro save_errno = errno; 261364562Sgshapiro if (tTd(16, 1)) 261490792Sgshapiro sm_dprintf("Connect failed (%s)\n", 261590792Sgshapiro sm_errstring(save_errno)); 261690792Sgshapiro#if XLA 261738032Speter xla_host_end(host); 261890792Sgshapiro#endif /* XLA */ 261938032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 262090792Sgshapiro#if NETINET6 262171345Sgshapiro if (hp != NULL) 262271345Sgshapiro freehostent(hp); 262390792Sgshapiro#endif /* NETINET6 */ 262464562Sgshapiro errno = save_errno; 262538032Speter return EX_TEMPFAIL; 262638032Speter } 262738032Speter 262890792Sgshapiro#if NETINET6 262971345Sgshapiro if (hp != NULL) 263071345Sgshapiro { 263171345Sgshapiro freehostent(hp); 263271345Sgshapiro hp = NULL; 263371345Sgshapiro } 263490792Sgshapiro#endif /* NETINET6 */ 263571345Sgshapiro 263638032Speter /* connection ok, put it into canonical form */ 263764562Sgshapiro mci->mci_out = NULL; 263890792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 263990792Sgshapiro (void *) &s, 264090792Sgshapiro SM_IO_WRONLY, NULL)) == NULL || 264138032Speter (s = dup(s)) < 0 || 264290792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 264390792Sgshapiro (void *) &s, 264490792Sgshapiro SM_IO_RDONLY, NULL)) == NULL) 264538032Speter { 264664562Sgshapiro save_errno = errno; 264738032Speter syserr("cannot open SMTP client channel, fd=%d", s); 264838032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 264964562Sgshapiro if (mci->mci_out != NULL) 265090792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 265164562Sgshapiro (void) close(s); 265264562Sgshapiro errno = save_errno; 265338032Speter return EX_TEMPFAIL; 265438032Speter } 265590792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 265638032Speter 265790792Sgshapiro /* set {client_flags} */ 265890792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 265990792Sgshapiro { 266090792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 266190792Sgshapiro macid("{client_flags}"), 266290792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 266390792Sgshapiro } 266490792Sgshapiro else 266590792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 266690792Sgshapiro macid("{client_flags}"), ""); 266790792Sgshapiro 266890792Sgshapiro /* "add" {client_flags} to bitmap */ 266990792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 267090792Sgshapiro { 267190792Sgshapiro /* look for just this one flag */ 267290792Sgshapiro setbitn(D_IFNHELO, d_flags); 267390792Sgshapiro } 267490792Sgshapiro 267564562Sgshapiro /* find out name for Interface through which we connect */ 267664562Sgshapiro len = sizeof addr; 267764562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 267864562Sgshapiro { 267964562Sgshapiro char *name; 268090792Sgshapiro char family[5]; 268164562Sgshapiro 268290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 268390792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 268490792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 268590792Sgshapiro addr.sa.sa_family); 268690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 268790792Sgshapiro macid("{if_family_out}"), family); 268864562Sgshapiro 268964562Sgshapiro name = hostnamebyanyaddr(&addr); 269090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 269190792Sgshapiro macid("{if_name_out}"), name); 269264562Sgshapiro if (LogLevel > 11) 269364562Sgshapiro { 269464562Sgshapiro /* log connection information */ 269564562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 269664562Sgshapiro "SMTP outgoing connect on %.40s", name); 269764562Sgshapiro } 269864562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 269964562Sgshapiro { 270064562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 270164562Sgshapiro mci->mci_heloname = newstr(name); 270264562Sgshapiro } 270364562Sgshapiro } 270464562Sgshapiro else 270564562Sgshapiro { 270690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 270790792Sgshapiro macid("{if_name_out}"), NULL); 270890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 270990792Sgshapiro macid("{if_addr_out}"), NULL); 271090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 271190792Sgshapiro macid("{if_family_out}"), NULL); 271264562Sgshapiro } 271338032Speter mci_setstat(mci, EX_OK, NULL, NULL); 271464562Sgshapiro return EX_OK; 271538032Speter} 271664562Sgshapiro 271764562Sgshapirostatic void 271864562Sgshapiroconnecttimeout() 271964562Sgshapiro{ 272077349Sgshapiro /* 272177349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 272277349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 272377349Sgshapiro ** DOING. 272477349Sgshapiro */ 272577349Sgshapiro 272664562Sgshapiro errno = ETIMEDOUT; 272764562Sgshapiro longjmp(CtxConnectTimeout, 1); 272864562Sgshapiro} 272990792Sgshapiro/* 273064562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 273164562Sgshapiro** 273264562Sgshapiro** Parameters: 273364562Sgshapiro** mux_path -- the path of the socket to connect to. 273464562Sgshapiro** mci -- a pointer to the mail connection information 273564562Sgshapiro** structure to be filled in. 273664562Sgshapiro** 273764562Sgshapiro** Returns: 273864562Sgshapiro** An exit code telling whether the connection could be 273964562Sgshapiro** made and if not why not. 274064562Sgshapiro** 274164562Sgshapiro** Side Effects: 274264562Sgshapiro** none. 274364562Sgshapiro*/ 274464562Sgshapiro 274590792Sgshapiro#if NETUNIX 274690792Sgshapiroint 274790792Sgshapiromakeconnection_ds(mux_path, mci) 274864562Sgshapiro char *mux_path; 274964562Sgshapiro register MCI *mci; 275064562Sgshapiro{ 275164562Sgshapiro int sock; 275264562Sgshapiro int rval, save_errno; 275364562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 275464562Sgshapiro struct sockaddr_un unix_addr; 275564562Sgshapiro 275664562Sgshapiro /* if not safe, don't connect */ 275764562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 275864562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 275964562Sgshapiro 276064562Sgshapiro if (rval != 0) 276164562Sgshapiro { 276264562Sgshapiro syserr("makeconnection_ds: unsafe domain socket"); 276364562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 276464562Sgshapiro errno = rval; 276564562Sgshapiro return EX_TEMPFAIL; 276664562Sgshapiro } 276764562Sgshapiro 276864562Sgshapiro /* prepare address structure */ 276964562Sgshapiro memset(&unix_addr, '\0', sizeof unix_addr); 277064562Sgshapiro unix_addr.sun_family = AF_UNIX; 277164562Sgshapiro 277264562Sgshapiro if (strlen(mux_path) >= sizeof unix_addr.sun_path) 277364562Sgshapiro { 277464562Sgshapiro syserr("makeconnection_ds: domain socket name too long"); 277590792Sgshapiro 277690792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 277764562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 277864562Sgshapiro errno = ENAMETOOLONG; 277964562Sgshapiro return EX_UNAVAILABLE; 278064562Sgshapiro } 278190792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 278290792Sgshapiro sizeof unix_addr.sun_path); 278364562Sgshapiro 278464562Sgshapiro /* initialize domain socket */ 278564562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 278664562Sgshapiro if (sock == -1) 278764562Sgshapiro { 278864562Sgshapiro save_errno = errno; 278964562Sgshapiro syserr("makeconnection_ds: could not create domain socket"); 279064562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 279164562Sgshapiro errno = save_errno; 279264562Sgshapiro return EX_TEMPFAIL; 279364562Sgshapiro } 279464562Sgshapiro 279564562Sgshapiro /* connect to server */ 279664562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 279764562Sgshapiro sizeof(unix_addr)) == -1) 279864562Sgshapiro { 279964562Sgshapiro save_errno = errno; 280064562Sgshapiro syserr("Could not connect to socket %s", mux_path); 280164562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 280264562Sgshapiro (void) close(sock); 280364562Sgshapiro errno = save_errno; 280464562Sgshapiro return EX_TEMPFAIL; 280564562Sgshapiro } 280664562Sgshapiro 280764562Sgshapiro /* connection ok, put it into canonical form */ 280864562Sgshapiro mci->mci_out = NULL; 280990792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 281090792Sgshapiro (void *) &sock, SM_IO_WRONLY, NULL)) 281190792Sgshapiro == NULL 281290792Sgshapiro || (sock = dup(sock)) < 0 || 281390792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 281490792Sgshapiro (void *) &sock, SM_IO_RDONLY, NULL)) 281590792Sgshapiro == NULL) 281664562Sgshapiro { 281764562Sgshapiro save_errno = errno; 281864562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 281964562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 282064562Sgshapiro if (mci->mci_out != NULL) 282190792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 282264562Sgshapiro (void) close(sock); 282364562Sgshapiro errno = save_errno; 282464562Sgshapiro return EX_TEMPFAIL; 282564562Sgshapiro } 282690792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 282764562Sgshapiro 282864562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 282964562Sgshapiro errno = 0; 283064562Sgshapiro return EX_OK; 283164562Sgshapiro} 283290792Sgshapiro#endif /* NETUNIX */ 283390792Sgshapiro/* 283490792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 283577349Sgshapiro** 283677349Sgshapiro** Parameters: 283790792Sgshapiro** none. 283877349Sgshapiro** 283977349Sgshapiro** Returns: 284077349Sgshapiro** none. 284177349Sgshapiro** 284277349Sgshapiro** Side Effects: 284390792Sgshapiro** closes control socket, exits. 284477349Sgshapiro*/ 284577349Sgshapiro 284690792Sgshapirovoid 284790792Sgshapiroshutdown_daemon() 284877349Sgshapiro{ 284990792Sgshapiro int i; 285090792Sgshapiro char *reason; 285177349Sgshapiro 285290792Sgshapiro sm_allsignals(true); 285390792Sgshapiro 285490792Sgshapiro reason = ShutdownRequest; 285590792Sgshapiro ShutdownRequest = NULL; 285690792Sgshapiro PendingSignal = 0; 285790792Sgshapiro 285890792Sgshapiro if (LogLevel > 79) 285990792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)", 286090792Sgshapiro reason == NULL ? "implicit call" : reason); 286190792Sgshapiro 286290792Sgshapiro FileName = NULL; 286390792Sgshapiro closecontrolsocket(true); 286490792Sgshapiro#if XLA 286590792Sgshapiro xla_all_end(); 286690792Sgshapiro#endif /* XLA */ 286790792Sgshapiro 286890792Sgshapiro for (i = 0; i < NDaemons; i++) 286990792Sgshapiro { 287090792Sgshapiro if (Daemons[i].d_socket >= 0) 287190792Sgshapiro { 287290792Sgshapiro (void) close(Daemons[i].d_socket); 287390792Sgshapiro Daemons[i].d_socket = -1; 287490792Sgshapiro 287590792Sgshapiro#if _FFR_DAEMON_NETUNIX 287690792Sgshapiro# if NETUNIX 287790792Sgshapiro /* Remove named sockets */ 287890792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 287990792Sgshapiro { 288090792Sgshapiro int rval; 288190792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 288290792Sgshapiro 288390792Sgshapiro /* if not safe, don't use it */ 288490792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 288590792Sgshapiro RunAsUid, RunAsGid, 288690792Sgshapiro RunAsUserName, sff, 288790792Sgshapiro S_IRUSR|S_IWUSR, NULL); 288890792Sgshapiro if (rval == 0 && 288990792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 289090792Sgshapiro { 289190792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 289290792Sgshapiro "Could not remove daemon %s socket: %s: %s", 289390792Sgshapiro Daemons[i].d_name, 289490792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 289590792Sgshapiro sm_errstring(errno)); 289690792Sgshapiro } 289790792Sgshapiro } 289890792Sgshapiro# endif /* NETUNIX */ 289990792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */ 290090792Sgshapiro } 290190792Sgshapiro } 290290792Sgshapiro 290390792Sgshapiro finis(false, true, EX_OK); 290477349Sgshapiro} 290590792Sgshapiro/* 290677349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 290777349Sgshapiro** 290877349Sgshapiro** Parameters: 290977349Sgshapiro** none. 291077349Sgshapiro** 291177349Sgshapiro** Returns: 291277349Sgshapiro** none. 291377349Sgshapiro** 291477349Sgshapiro** Side Effects: 291577349Sgshapiro** restarts the daemon or exits if restart fails. 291677349Sgshapiro*/ 291777349Sgshapiro 291880785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 291980785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 292080785Sgshapirodo \ 292180785Sgshapiro{ \ 292290792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 292380785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 292490792Sgshapiro (void) sm_signal((sig), (old)); \ 292580785Sgshapiro} while (0) 292680785Sgshapiro 292790792Sgshapirovoid 292877349Sgshapirorestart_daemon() 292977349Sgshapiro{ 293090792Sgshapiro bool drop; 293177349Sgshapiro int i; 293277349Sgshapiro int save_errno; 293377349Sgshapiro char *reason; 293480785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 293577349Sgshapiro extern int DtableSize; 293677349Sgshapiro 293780785Sgshapiro /* clear the events to turn off SIGALRMs */ 293890792Sgshapiro sm_clear_events(); 293990792Sgshapiro sm_allsignals(true); 294077349Sgshapiro 294177349Sgshapiro reason = RestartRequest; 294277349Sgshapiro RestartRequest = NULL; 294377349Sgshapiro PendingSignal = 0; 294477349Sgshapiro 294577349Sgshapiro if (SaveArgv[0][0] != '/') 294677349Sgshapiro { 294777349Sgshapiro if (LogLevel > 3) 294877349Sgshapiro sm_syslog(LOG_INFO, NOQID, 294977349Sgshapiro "could not restart: need full path"); 295090792Sgshapiro finis(false, true, EX_OSFILE); 295190792Sgshapiro /* NOTREACHED */ 295277349Sgshapiro } 295377349Sgshapiro if (LogLevel > 3) 295477349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 295577349Sgshapiro SaveArgv[0], 295677349Sgshapiro reason == NULL ? "implicit call" : reason); 295777349Sgshapiro 295890792Sgshapiro closecontrolsocket(true); 295998121Sgshapiro#if SM_CONF_SHM 296098121Sgshapiro cleanup_shm(DaemonPid == getpid()); 296198121Sgshapiro#endif /* SM_CONF_SHM */ 296290792Sgshapiro 296390792Sgshapiro /* 296490792Sgshapiro ** Want to drop to the user who started the process in all cases 296590792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 296690792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 296790792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 296890792Sgshapiro */ 296990792Sgshapiro 297090792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 297190792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 297290792Sgshapiro 297390792Sgshapiro if (drop_privileges(drop) != EX_OK) 297477349Sgshapiro { 297577349Sgshapiro if (LogLevel > 0) 297677349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 297790792Sgshapiro "could not drop privileges: %s", 297890792Sgshapiro sm_errstring(errno)); 297990792Sgshapiro finis(false, true, EX_OSERR); 298090792Sgshapiro /* NOTREACHED */ 298177349Sgshapiro } 298277349Sgshapiro 298377349Sgshapiro /* arrange for all the files to be closed */ 298477349Sgshapiro for (i = 3; i < DtableSize; i++) 298577349Sgshapiro { 298677349Sgshapiro register int j; 298777349Sgshapiro 298877349Sgshapiro if ((j = fcntl(i, F_GETFD, 0)) != -1) 298977349Sgshapiro (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); 299077349Sgshapiro } 299177349Sgshapiro 299280785Sgshapiro /* 299380785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 299480785Sgshapiro ** However, the default action can be "terminate", so it isn't 299580785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 299680785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 299780785Sgshapiro */ 299880785Sgshapiro 299980785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 300080785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 300180785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 300280785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 300380785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 300480785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 300580785Sgshapiro#ifdef SIGUSR1 300680785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 300780785Sgshapiro#endif /* SIGUSR1 */ 300894334Sgshapiro 300994334Sgshapiro /* Turn back on signals */ 301090792Sgshapiro sm_allsignals(false); 301177349Sgshapiro 301277349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 301377349Sgshapiro save_errno = errno; 301477349Sgshapiro 301580785Sgshapiro /* block signals again and restore needed signals */ 301690792Sgshapiro sm_allsignals(true); 301780785Sgshapiro 301880785Sgshapiro /* For finis() events */ 301990792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 302080785Sgshapiro 302180785Sgshapiro#ifdef SIGUSR1 302280785Sgshapiro /* For debugging finis() */ 302390792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 302480785Sgshapiro#endif /* SIGUSR1 */ 302577349Sgshapiro 302677349Sgshapiro errno = save_errno; 302777349Sgshapiro if (LogLevel > 0) 302890792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 302990792Sgshapiro SaveArgv[0], sm_errstring(errno)); 303090792Sgshapiro finis(false, true, EX_OSFILE); 303190792Sgshapiro /* NOTREACHED */ 303277349Sgshapiro} 303390792Sgshapiro/* 303438032Speter** MYHOSTNAME -- return the name of this host. 303538032Speter** 303638032Speter** Parameters: 303738032Speter** hostbuf -- a place to return the name of this host. 303838032Speter** size -- the size of hostbuf. 303938032Speter** 304038032Speter** Returns: 304138032Speter** A list of aliases for this host. 304238032Speter** 304338032Speter** Side Effects: 304438032Speter** Adds numeric codes to $=w. 304538032Speter*/ 304638032Speter 304738032Speterstruct hostent * 304838032Spetermyhostname(hostbuf, size) 304938032Speter char hostbuf[]; 305038032Speter int size; 305138032Speter{ 305238032Speter register struct hostent *hp; 305338032Speter 305473188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 305590792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 305664562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 305790792Sgshapiro#if NETINET && NETINET6 305880785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 305980785Sgshapiro { 306080785Sgshapiro /* 306180785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 306280785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 306380785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 306480785Sgshapiro */ 306580785Sgshapiro 306680785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 306780785Sgshapiro } 306890792Sgshapiro#endif /* NETINET && NETINET6 */ 306938032Speter if (hp == NULL) 307038032Speter return NULL; 307138032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 307264562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 307364562Sgshapiro 307490792Sgshapiro#if NETINFO 307564562Sgshapiro if (strchr(hostbuf, '.') == NULL) 307638032Speter { 307764562Sgshapiro char *domainname; 307864562Sgshapiro 307964562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 308064562Sgshapiro "domain", '\0'); 308164562Sgshapiro if (domainname != NULL && 308264562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 308390792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 308438032Speter } 308590792Sgshapiro#endif /* NETINFO */ 308638032Speter 308738032Speter /* 308838032Speter ** If there is still no dot in the name, try looking for a 308938032Speter ** dotted alias. 309038032Speter */ 309138032Speter 309238032Speter if (strchr(hostbuf, '.') == NULL) 309338032Speter { 309438032Speter char **ha; 309538032Speter 309664562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 309738032Speter { 309838032Speter if (strchr(*ha, '.') != NULL) 309938032Speter { 310064562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 310138032Speter hostbuf[size - 1] = '\0'; 310238032Speter break; 310338032Speter } 310438032Speter } 310538032Speter } 310638032Speter 310738032Speter /* 310838032Speter ** If _still_ no dot, wait for a while and try again -- it is 310938032Speter ** possible that some service is starting up. This can result 311038032Speter ** in excessive delays if the system is badly configured, but 311138032Speter ** there really isn't a way around that, particularly given that 311238032Speter ** the config file hasn't been read at this point. 311338032Speter ** All in all, a bit of a mess. 311438032Speter */ 311538032Speter 311638032Speter if (strchr(hostbuf, '.') == NULL && 311790792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 311838032Speter { 311938032Speter sm_syslog(LOG_CRIT, NOQID, 312064562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 312164562Sgshapiro hostbuf); 312238032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 312338032Speter hostbuf); 312464562Sgshapiro (void) sleep(60); 312590792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 312638032Speter { 312738032Speter sm_syslog(LOG_ALERT, NOQID, 312864562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 312964562Sgshapiro hostbuf); 313038032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 313138032Speter hostbuf); 313238032Speter } 313338032Speter } 313464562Sgshapiro return hp; 313538032Speter} 313690792Sgshapiro/* 313738032Speter** ADDRCMP -- compare two host addresses 313838032Speter** 313938032Speter** Parameters: 314038032Speter** hp -- hostent structure for the first address 314138032Speter** ha -- actual first address 314238032Speter** sa -- second address 314338032Speter** 314438032Speter** Returns: 314538032Speter** 0 -- if ha and sa match 314638032Speter** else -- they don't match 314738032Speter*/ 314838032Speter 314964562Sgshapirostatic int 315038032Speteraddrcmp(hp, ha, sa) 315138032Speter struct hostent *hp; 315238032Speter char *ha; 315338032Speter SOCKADDR *sa; 315438032Speter{ 315590792Sgshapiro#if NETINET6 315690792Sgshapiro unsigned char *a; 315790792Sgshapiro#endif /* NETINET6 */ 315864562Sgshapiro 315938032Speter switch (sa->sa.sa_family) 316038032Speter { 316190792Sgshapiro#if NETINET 316238032Speter case AF_INET: 316338032Speter if (hp->h_addrtype == AF_INET) 316464562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 316538032Speter break; 316690792Sgshapiro#endif /* NETINET */ 316738032Speter 316890792Sgshapiro#if NETINET6 316964562Sgshapiro case AF_INET6: 317090792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 317164562Sgshapiro 317264562Sgshapiro /* Straight binary comparison */ 317364562Sgshapiro if (hp->h_addrtype == AF_INET6) 317464562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 317564562Sgshapiro 317664562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 317764562Sgshapiro if (hp->h_addrtype == AF_INET && 317864562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 317964562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 318064562Sgshapiro break; 318190792Sgshapiro#endif /* NETINET6 */ 318238032Speter } 318338032Speter return -1; 318438032Speter} 318590792Sgshapiro/* 318664562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 318738032Speter** 318838032Speter** Uses RFC1413 protocol to try to get info from the other end. 318938032Speter** 319038032Speter** Parameters: 319138032Speter** fd -- the descriptor 319290792Sgshapiro** may_be_forged -- an outage that is set to true if the 319338032Speter** forward lookup of RealHostName does not match 319490792Sgshapiro** RealHostAddr; set to false if they do match. 319538032Speter** 319638032Speter** Returns: 319738032Speter** The user@host information associated with this descriptor. 319838032Speter*/ 319938032Speter 320038032Speterstatic jmp_buf CtxAuthTimeout; 320138032Speter 320238032Speterstatic void 320338032Speterauthtimeout() 320438032Speter{ 320577349Sgshapiro /* 320677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 320777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 320877349Sgshapiro ** DOING. 320977349Sgshapiro */ 321077349Sgshapiro 321177349Sgshapiro errno = ETIMEDOUT; 321238032Speter longjmp(CtxAuthTimeout, 1); 321338032Speter} 321438032Speter 321538032Speterchar * 321638032Spetergetauthinfo(fd, may_be_forged) 321738032Speter int fd; 321838032Speter bool *may_be_forged; 321938032Speter{ 322090792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 322138032Speter SOCKADDR_LEN_T falen; 322238032Speter register char *volatile p = NULL; 322338032Speter SOCKADDR la; 322438032Speter SOCKADDR_LEN_T lalen; 322590792Sgshapiro#ifndef NO_GETSERVBYNAME 322638032Speter register struct servent *sp; 322790792Sgshapiro# if NETINET 322890792Sgshapiro static unsigned short port4 = 0; 322990792Sgshapiro# endif /* NETINET */ 323090792Sgshapiro# if NETINET6 323190792Sgshapiro static unsigned short port6 = 0; 323290792Sgshapiro# endif /* NETINET6 */ 323390792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 323438032Speter volatile int s; 323538032Speter int i = 0; 323690792Sgshapiro size_t len; 323790792Sgshapiro SM_EVENT *ev; 323838032Speter int nleft; 323938032Speter struct hostent *hp; 324038032Speter char *ostype = NULL; 324138032Speter char **ha; 324238032Speter char ibuf[MAXNAME + 1]; 324338032Speter static char hbuf[MAXNAME * 2 + 11]; 324438032Speter 324590792Sgshapiro *may_be_forged = false; 324638032Speter falen = sizeof RealHostAddr; 324738032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 324838032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 324938032Speter { 325064562Sgshapiro if (i < 0) 325164562Sgshapiro { 325264562Sgshapiro /* 325364562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 325464562Sgshapiro ** errno in this case, so a mis-report doesn't 325564562Sgshapiro ** happen later. 325664562Sgshapiro */ 325790792Sgshapiro 325864562Sgshapiro if (errno != ENOTSOCK) 325964562Sgshapiro return NULL; 326064562Sgshapiro errno = 0; 326164562Sgshapiro } 326290792Sgshapiro (void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName, 326390792Sgshapiro "@localhost"); 326438032Speter if (tTd(9, 1)) 326590792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 326638032Speter return hbuf; 326738032Speter } 326838032Speter 326938032Speter if (RealHostName == NULL) 327038032Speter { 327138032Speter /* translate that to a host name */ 327238032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 327338032Speter if (strlen(RealHostName) > MAXNAME) 327490792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 327538032Speter } 327638032Speter 327738032Speter /* cross check RealHostName with forward DNS lookup */ 327890792Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] != '[' && 327990792Sgshapiro RealHostName[0] != '[') 328038032Speter { 328180785Sgshapiro int family; 328280785Sgshapiro 328380785Sgshapiro family = RealHostAddr.sa.sa_family; 328490792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 328580785Sgshapiro /* 328680785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 328780785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 328880785Sgshapiro ** address(es) for addrcmp() to compare against 328980785Sgshapiro ** RealHostAddr. 329080785Sgshapiro ** 329180785Sgshapiro ** Actually, we only need to do this for systems 329280785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 329380785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 329480785Sgshapiro ** flag. A better fix to this problem is to add this 329580785Sgshapiro ** functionality to our stub getipnodebyname(). 329680785Sgshapiro */ 329780785Sgshapiro 329880785Sgshapiro if (family == AF_INET6 && 329980785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 330080785Sgshapiro family = AF_INET; 330190792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 330280785Sgshapiro 330338032Speter /* try to match the reverse against the forward lookup */ 330480785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 330538032Speter if (hp == NULL) 330690792Sgshapiro *may_be_forged = true; 330738032Speter else 330838032Speter { 330938032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 331090792Sgshapiro { 331138032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 331238032Speter break; 331390792Sgshapiro } 331438032Speter *may_be_forged = *ha == NULL; 331590792Sgshapiro#if NETINET6 331671345Sgshapiro freehostent(hp); 331771345Sgshapiro hp = NULL; 331890792Sgshapiro#endif /* NETINET6 */ 331938032Speter } 332038032Speter } 332138032Speter 332238032Speter if (TimeOuts.to_ident == 0) 332338032Speter goto noident; 332438032Speter 332538032Speter lalen = sizeof la; 332664562Sgshapiro switch (RealHostAddr.sa.sa_family) 332738032Speter { 332890792Sgshapiro#if NETINET 332964562Sgshapiro case AF_INET: 333064562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 333164562Sgshapiro lalen <= 0 || 333264562Sgshapiro la.sa.sa_family != AF_INET) 333364562Sgshapiro { 333464562Sgshapiro /* no ident info */ 333564562Sgshapiro goto noident; 333664562Sgshapiro } 333764562Sgshapiro port = RealHostAddr.sin.sin_port; 333838032Speter 333964562Sgshapiro /* create ident query */ 334090792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 334164562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 334264562Sgshapiro ntohs(la.sin.sin_port)); 334338032Speter 334464562Sgshapiro /* create local address */ 334564562Sgshapiro la.sin.sin_port = 0; 334638032Speter 334764562Sgshapiro /* create foreign address */ 334890792Sgshapiro# ifdef NO_GETSERVBYNAME 334938032Speter RealHostAddr.sin.sin_port = htons(113); 335090792Sgshapiro# else /* NO_GETSERVBYNAME */ 335190792Sgshapiro 335290792Sgshapiro /* 335390792Sgshapiro ** getservbyname() consumes about 5% of the time 335490792Sgshapiro ** when receiving a small message (almost all of the time 335590792Sgshapiro ** spent in this routine). 335690792Sgshapiro ** Hence we store the port in a static variable 335790792Sgshapiro ** to save this time. 335890792Sgshapiro ** The portnumber shouldn't change very often... 335990792Sgshapiro ** This code makes the assumption that the port number 336090792Sgshapiro ** is not 0. 336190792Sgshapiro */ 336290792Sgshapiro 336390792Sgshapiro if (port4 == 0) 336490792Sgshapiro { 336590792Sgshapiro sp = getservbyname("auth", "tcp"); 336690792Sgshapiro if (sp != NULL) 336790792Sgshapiro port4 = sp->s_port; 336890792Sgshapiro else 336990792Sgshapiro port4 = htons(113); 337090792Sgshapiro } 337190792Sgshapiro RealHostAddr.sin.sin_port = port4; 337264562Sgshapiro break; 337390792Sgshapiro# endif /* NO_GETSERVBYNAME */ 337490792Sgshapiro#endif /* NETINET */ 337538032Speter 337690792Sgshapiro#if NETINET6 337764562Sgshapiro case AF_INET6: 337864562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 337964562Sgshapiro lalen <= 0 || 338064562Sgshapiro la.sa.sa_family != AF_INET6) 338164562Sgshapiro { 338264562Sgshapiro /* no ident info */ 338364562Sgshapiro goto noident; 338464562Sgshapiro } 338564562Sgshapiro port = RealHostAddr.sin6.sin6_port; 338664562Sgshapiro 338764562Sgshapiro /* create ident query */ 338890792Sgshapiro (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 338964562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 339064562Sgshapiro ntohs(la.sin6.sin6_port)); 339164562Sgshapiro 339264562Sgshapiro /* create local address */ 339364562Sgshapiro la.sin6.sin6_port = 0; 339464562Sgshapiro 339564562Sgshapiro /* create foreign address */ 339690792Sgshapiro# ifdef NO_GETSERVBYNAME 339764562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 339890792Sgshapiro# else /* NO_GETSERVBYNAME */ 339990792Sgshapiro if (port6 == 0) 340090792Sgshapiro { 340190792Sgshapiro sp = getservbyname("auth", "tcp"); 340290792Sgshapiro if (sp != NULL) 340390792Sgshapiro port6 = sp->s_port; 340490792Sgshapiro else 340590792Sgshapiro port6 = htons(113); 340690792Sgshapiro } 340790792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 340864562Sgshapiro break; 340990792Sgshapiro# endif /* NO_GETSERVBYNAME */ 341090792Sgshapiro#endif /* NETINET6 */ 341164562Sgshapiro default: 341264562Sgshapiro /* no ident info */ 341364562Sgshapiro goto noident; 341464562Sgshapiro } 341564562Sgshapiro 341638032Speter s = -1; 341738032Speter if (setjmp(CtxAuthTimeout) != 0) 341838032Speter { 341938032Speter if (s >= 0) 342038032Speter (void) close(s); 342138032Speter goto noident; 342238032Speter } 342338032Speter 342438032Speter /* put a timeout around the whole thing */ 342590792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 342638032Speter 342764562Sgshapiro 342838032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 342964562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 343038032Speter if (s < 0) 343138032Speter { 343290792Sgshapiro sm_clrevent(ev); 343338032Speter goto noident; 343438032Speter } 343564562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 343664562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 343738032Speter goto closeident; 343838032Speter 343938032Speter if (tTd(9, 10)) 344090792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 344138032Speter 344238032Speter /* send query */ 344338032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 344438032Speter goto closeident; 344538032Speter 344638032Speter /* get result */ 344738032Speter p = &ibuf[0]; 344838032Speter nleft = sizeof ibuf - 1; 344938032Speter while ((i = read(s, p, nleft)) > 0) 345038032Speter { 345138032Speter p += i; 345238032Speter nleft -= i; 345338032Speter *p = '\0'; 345490792Sgshapiro if (strchr(ibuf, '\n') != NULL || nleft <= 0) 345538032Speter break; 345638032Speter } 345738032Speter (void) close(s); 345890792Sgshapiro sm_clrevent(ev); 345938032Speter if (i < 0 || p == &ibuf[0]) 346038032Speter goto noident; 346138032Speter 346238032Speter if (*--p == '\n' && *--p == '\r') 346338032Speter p--; 346438032Speter *++p = '\0'; 346538032Speter 346638032Speter if (tTd(9, 3)) 346790792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 346838032Speter 346938032Speter /* parse result */ 347038032Speter p = strchr(ibuf, ':'); 347138032Speter if (p == NULL) 347238032Speter { 347338032Speter /* malformed response */ 347438032Speter goto noident; 347538032Speter } 347638032Speter while (isascii(*++p) && isspace(*p)) 347738032Speter continue; 347890792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 347938032Speter { 348038032Speter /* presumably an error string */ 348138032Speter goto noident; 348238032Speter } 348338032Speter p += 6; 348438032Speter while (isascii(*p) && isspace(*p)) 348538032Speter p++; 348638032Speter if (*p++ != ':') 348738032Speter { 348838032Speter /* either useridxx or malformed response */ 348938032Speter goto noident; 349038032Speter } 349138032Speter 349238032Speter /* p now points to the OSTYPE field */ 349338032Speter while (isascii(*p) && isspace(*p)) 349438032Speter p++; 349538032Speter ostype = p; 349638032Speter p = strchr(p, ':'); 349738032Speter if (p == NULL) 349838032Speter { 349938032Speter /* malformed response */ 350038032Speter goto noident; 350138032Speter } 350238032Speter else 350338032Speter { 350438032Speter char *charset; 350538032Speter 350638032Speter *p = '\0'; 350738032Speter charset = strchr(ostype, ','); 350838032Speter if (charset != NULL) 350938032Speter *charset = '\0'; 351038032Speter } 351138032Speter 351238032Speter /* 1413 says don't do this -- but it's broken otherwise */ 351338032Speter while (isascii(*++p) && isspace(*p)) 351438032Speter continue; 351538032Speter 351638032Speter /* p now points to the authenticated name -- copy carefully */ 351790792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 351838032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 351938032Speter { 352090792Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf); 352138032Speter cleanstrcpy(&hbuf[6], p, MAXNAME); 352238032Speter } 352338032Speter else 352438032Speter cleanstrcpy(hbuf, p, MAXNAME); 352590792Sgshapiro len = strlen(hbuf); 352690792Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@", 352790792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 352838032Speter goto postident; 352938032Speter 353038032Spetercloseident: 353138032Speter (void) close(s); 353290792Sgshapiro sm_clrevent(ev); 353338032Speter 353438032Speternoident: 353564562Sgshapiro /* put back the original incoming port */ 353664562Sgshapiro switch (RealHostAddr.sa.sa_family) 353764562Sgshapiro { 353890792Sgshapiro#if NETINET 353964562Sgshapiro case AF_INET: 354064562Sgshapiro if (port > 0) 354164562Sgshapiro RealHostAddr.sin.sin_port = port; 354264562Sgshapiro break; 354390792Sgshapiro#endif /* NETINET */ 354464562Sgshapiro 354590792Sgshapiro#if NETINET6 354664562Sgshapiro case AF_INET6: 354764562Sgshapiro if (port > 0) 354864562Sgshapiro RealHostAddr.sin6.sin6_port = port; 354964562Sgshapiro break; 355090792Sgshapiro#endif /* NETINET6 */ 355164562Sgshapiro } 355264562Sgshapiro 355338032Speter if (RealHostName == NULL) 355438032Speter { 355538032Speter if (tTd(9, 1)) 355690792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 355738032Speter return NULL; 355838032Speter } 355990792Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf); 356038032Speter 356138032Speterpostident: 356290792Sgshapiro#if IP_SRCROUTE 356390792Sgshapiro# ifndef GET_IPOPT_DST 356490792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 356590792Sgshapiro# endif /* ! GET_IPOPT_DST */ 356638032Speter /* 356738032Speter ** Extract IP source routing information. 356838032Speter ** 356938032Speter ** Format of output for a connection from site a through b 357038032Speter ** through c to d: 357138032Speter ** loose: @site-c@site-b:site-a 357238032Speter ** strict: !@site-c@site-b:site-a 357338032Speter ** 357438032Speter ** o - pointer within ipopt_list structure. 357538032Speter ** q - pointer within ls/ss rr route data 357638032Speter ** p - pointer to hbuf 357738032Speter */ 357838032Speter 357938032Speter if (RealHostAddr.sa.sa_family == AF_INET) 358038032Speter { 358138032Speter SOCKOPT_LEN_T ipoptlen; 358238032Speter int j; 358390792Sgshapiro unsigned char *q; 358490792Sgshapiro unsigned char *o; 358538032Speter int l; 358664562Sgshapiro struct IPOPTION ipopt; 358738032Speter 358838032Speter ipoptlen = sizeof ipopt; 358938032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 359038032Speter (char *) &ipopt, &ipoptlen) < 0) 359138032Speter goto noipsr; 359238032Speter if (ipoptlen == 0) 359338032Speter goto noipsr; 359490792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 359590792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 359638032Speter { 359738032Speter switch (*o) 359838032Speter { 359964562Sgshapiro case IPOPT_EOL: 360038032Speter o = NULL; 360138032Speter break; 360238032Speter 360338032Speter case IPOPT_NOP: 360438032Speter o++; 360538032Speter break; 360638032Speter 360738032Speter case IPOPT_SSRR: 360838032Speter case IPOPT_LSRR: 360938032Speter /* 361038032Speter ** Source routing. 361138032Speter ** o[0] is the option type (loose/strict). 361238032Speter ** o[1] is the length of this option, 361338032Speter ** including option type and 361438032Speter ** length. 361538032Speter ** o[2] is the pointer into the route 361638032Speter ** data. 361738032Speter ** o[3] begins the route data. 361838032Speter */ 361938032Speter 362038032Speter p = &hbuf[strlen(hbuf)]; 362138032Speter l = sizeof hbuf - (hbuf - p) - 6; 362290792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 362390792Sgshapiro " [%s@%.*s", 362490792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 362590792Sgshapiro l > 240 ? 120 : l / 2, 362690792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 362738032Speter i = strlen(p); 362838032Speter p += i; 362938032Speter l -= strlen(p); 363038032Speter 363138032Speter j = o[1] / sizeof(struct in_addr) - 1; 363238032Speter 363338032Speter /* q skips length and router pointer to data */ 363438032Speter q = &o[3]; 363538032Speter for ( ; j >= 0; j--) 363638032Speter { 363764562Sgshapiro struct in_addr addr; 363864562Sgshapiro 363938032Speter memcpy(&addr, q, sizeof(addr)); 364090792Sgshapiro (void) sm_snprintf(p, 364190792Sgshapiro SPACELEFT(hbuf, p), 364290792Sgshapiro "%c%.*s", 364390792Sgshapiro j != 0 ? '@' : ':', 364490792Sgshapiro l > 240 ? 120 : 364590792Sgshapiro j == 0 ? l : l / 2, 364690792Sgshapiro inet_ntoa(addr)); 364738032Speter i = strlen(p); 364838032Speter p += i; 364938032Speter l -= i + 1; 365064562Sgshapiro q += sizeof(struct in_addr); 365138032Speter } 365238032Speter o += o[1]; 365338032Speter break; 365438032Speter 365538032Speter default: 365638032Speter /* Skip over option */ 365738032Speter o += o[1]; 365838032Speter break; 365938032Speter } 366038032Speter } 366190792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 366238032Speter goto postipsr; 366338032Speter } 366438032Speter 366538032Speternoipsr: 366690792Sgshapiro#endif /* IP_SRCROUTE */ 366738032Speter if (RealHostName != NULL && RealHostName[0] != '[') 366838032Speter { 366938032Speter p = &hbuf[strlen(hbuf)]; 367090792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 367190792Sgshapiro anynet_ntoa(&RealHostAddr)); 367238032Speter } 367338032Speter if (*may_be_forged) 367438032Speter { 367538032Speter p = &hbuf[strlen(hbuf)]; 367690792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 367790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 367890792Sgshapiro macid("{client_resolve}"), "FORGED"); 367938032Speter } 368038032Speter 368190792Sgshapiro#if IP_SRCROUTE 368238032Speterpostipsr: 368390792Sgshapiro#endif /* IP_SRCROUTE */ 368464562Sgshapiro 368564562Sgshapiro /* put back the original incoming port */ 368664562Sgshapiro switch (RealHostAddr.sa.sa_family) 368764562Sgshapiro { 368890792Sgshapiro#if NETINET 368964562Sgshapiro case AF_INET: 369064562Sgshapiro if (port > 0) 369164562Sgshapiro RealHostAddr.sin.sin_port = port; 369264562Sgshapiro break; 369390792Sgshapiro#endif /* NETINET */ 369464562Sgshapiro 369590792Sgshapiro#if NETINET6 369664562Sgshapiro case AF_INET6: 369764562Sgshapiro if (port > 0) 369864562Sgshapiro RealHostAddr.sin6.sin6_port = port; 369964562Sgshapiro break; 370090792Sgshapiro#endif /* NETINET6 */ 370164562Sgshapiro } 370264562Sgshapiro 370390792Sgshapiro if (tTd(9, 1)) 370490792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 370538032Speter return hbuf; 370638032Speter} 370790792Sgshapiro/* 370838032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 370938032Speter** 371038032Speter** Parameters: 371138032Speter** map -- a pointer to this map. 371238032Speter** name -- the (presumably unqualified) hostname. 371338032Speter** av -- unused -- for compatibility with other mapping 371438032Speter** functions. 371538032Speter** statp -- an exit status (out parameter) -- set to 371638032Speter** EX_TEMPFAIL if the name server is unavailable. 371738032Speter** 371838032Speter** Returns: 371938032Speter** The mapping, if found. 372038032Speter** NULL if no mapping found. 372138032Speter** 372238032Speter** Side Effects: 372338032Speter** Looks up the host specified in hbuf. If it is not 372438032Speter** the canonical name for that host, return the canonical 372538032Speter** name (unless MF_MATCHONLY is set, which will cause the 372638032Speter** status only to be returned). 372738032Speter*/ 372838032Speter 372938032Speterchar * 373038032Speterhost_map_lookup(map, name, av, statp) 373138032Speter MAP *map; 373238032Speter char *name; 373338032Speter char **av; 373438032Speter int *statp; 373538032Speter{ 373638032Speter register struct hostent *hp; 373790792Sgshapiro#if NETINET 373838032Speter struct in_addr in_addr; 373990792Sgshapiro#endif /* NETINET */ 374090792Sgshapiro#if NETINET6 374164562Sgshapiro struct in6_addr in6_addr; 374290792Sgshapiro#endif /* NETINET6 */ 374364562Sgshapiro char *cp, *ans = NULL; 374438032Speter register STAB *s; 374590792Sgshapiro time_t now; 374690792Sgshapiro#if NAMED_BIND 374790792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 374890792Sgshapiro int SM_NONVOLATILE retry = 0; 374990792Sgshapiro#endif /* NAMED_BIND */ 375038032Speter char hbuf[MAXNAME + 1]; 375138032Speter 375238032Speter /* 375338032Speter ** See if we have already looked up this name. If so, just 375490792Sgshapiro ** return it (unless expired). 375538032Speter */ 375638032Speter 375790792Sgshapiro now = curtime(); 375838032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 375990792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 376090792Sgshapiro s->s_namecanon.nc_exp >= now) 376138032Speter { 376238032Speter if (tTd(9, 1)) 376390792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 376490792Sgshapiro name, 376590792Sgshapiro s->s_namecanon.nc_cname == NULL 376638032Speter ? "NULL" 376738032Speter : s->s_namecanon.nc_cname); 376838032Speter errno = s->s_namecanon.nc_errno; 376973188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 377038032Speter *statp = s->s_namecanon.nc_stat; 377138032Speter if (*statp == EX_TEMPFAIL) 377238032Speter { 377338032Speter CurEnv->e_status = "4.4.3"; 377438032Speter message("851 %s: Name server timeout", 377538032Speter shortenstring(name, 33)); 377638032Speter } 377738032Speter if (*statp != EX_OK) 377838032Speter return NULL; 377938032Speter if (s->s_namecanon.nc_cname == NULL) 378038032Speter { 378138032Speter syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", 378264562Sgshapiro name, 378364562Sgshapiro s->s_namecanon.nc_errno, 378464562Sgshapiro s->s_namecanon.nc_herrno); 378538032Speter return NULL; 378638032Speter } 378738032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 378838032Speter cp = map_rewrite(map, name, strlen(name), NULL); 378938032Speter else 379038032Speter cp = map_rewrite(map, 379138032Speter s->s_namecanon.nc_cname, 379238032Speter strlen(s->s_namecanon.nc_cname), 379338032Speter av); 379438032Speter return cp; 379538032Speter } 379638032Speter 379738032Speter /* 379838032Speter ** If we are running without a regular network connection (usually 379938032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 380038032Speter ** lookups because those could try to connect to a server. 380138032Speter */ 380238032Speter 380364562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 380464562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 380538032Speter { 380638032Speter if (tTd(9, 1)) 380790792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 380838032Speter *statp = EX_TEMPFAIL; 380938032Speter return NULL; 381038032Speter } 381138032Speter 381238032Speter /* 381338032Speter ** If first character is a bracket, then it is an address 381438032Speter ** lookup. Address is copied into a temporary buffer to 381538032Speter ** strip the brackets and to preserve name if address is 381638032Speter ** unknown. 381738032Speter */ 381838032Speter 381964562Sgshapiro if (tTd(9, 1)) 382090792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 382190792Sgshapiro#if NAMED_BIND 382290792Sgshapiro if (map->map_timeout > 0) 382390792Sgshapiro { 382490792Sgshapiro retrans = _res.retrans; 382590792Sgshapiro _res.retrans = map->map_timeout; 382690792Sgshapiro } 382790792Sgshapiro if (map->map_retry > 0) 382890792Sgshapiro { 382990792Sgshapiro retry = _res.retry; 383090792Sgshapiro _res.retry = map->map_retry; 383190792Sgshapiro } 383290792Sgshapiro#endif /* NAMED_BIND */ 383390792Sgshapiro 383490792Sgshapiro /* set default TTL */ 383590792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 383638032Speter if (*name != '[') 383738032Speter { 383890792Sgshapiro int ttl; 383990792Sgshapiro 384090792Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof hbuf); 384190792Sgshapiro if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl)) 384290792Sgshapiro { 384364562Sgshapiro ans = hbuf; 384490792Sgshapiro if (ttl > 0) 384590792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 384690792Sgshapiro SM_DEFAULT_TTL); 384790792Sgshapiro } 384864562Sgshapiro } 384964562Sgshapiro else 385064562Sgshapiro { 385164562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 385271345Sgshapiro { 385371345Sgshapiro if (tTd(9, 1)) 385490792Sgshapiro sm_dprintf("FAILED\n"); 385564562Sgshapiro return NULL; 385671345Sgshapiro } 385764562Sgshapiro *cp = '\0'; 385864562Sgshapiro 385964562Sgshapiro hp = NULL; 386090792Sgshapiro#if NETINET 386164562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 386264562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 386364562Sgshapiro INADDRSZ, AF_INET); 386490792Sgshapiro#endif /* NETINET */ 386590792Sgshapiro#if NETINET6 386664562Sgshapiro if (hp == NULL && 386790792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 386864562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 386964562Sgshapiro IN6ADDRSZ, AF_INET6); 387090792Sgshapiro#endif /* NETINET6 */ 387164562Sgshapiro *cp = ']'; 387264562Sgshapiro 387364562Sgshapiro if (hp != NULL) 387438032Speter { 387564562Sgshapiro /* found a match -- copy out */ 387690792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 387790792Sgshapiro#if NETINET6 387890792Sgshapiro if (ans == hp->h_name) 387990792Sgshapiro { 388090792Sgshapiro static char n[MAXNAME + 1]; 388190792Sgshapiro 388290792Sgshapiro /* hp->h_name is about to disappear */ 388390792Sgshapiro (void) sm_strlcpy(n, ans, sizeof n); 388490792Sgshapiro ans = n; 388590792Sgshapiro } 388671345Sgshapiro freehostent(hp); 388771345Sgshapiro hp = NULL; 388890792Sgshapiro#endif /* NETINET6 */ 388938032Speter } 389064562Sgshapiro } 389190792Sgshapiro#if NAMED_BIND 389290792Sgshapiro if (map->map_timeout > 0) 389390792Sgshapiro _res.retrans = retrans; 389490792Sgshapiro if (map->map_retry > 0) 389590792Sgshapiro _res.retry = retry; 389690792Sgshapiro#endif /* NAMED_BIND */ 389738032Speter 389864562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 389938032Speter 390064562Sgshapiro /* Found an answer */ 390164562Sgshapiro if (ans != NULL) 390264562Sgshapiro { 390364562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 390490792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 390590792Sgshapiro sm_free(s->s_namecanon.nc_cname); 390690792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 390764562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 390864562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 390964562Sgshapiro else 391064562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 391171345Sgshapiro if (tTd(9, 1)) 391290792Sgshapiro sm_dprintf("FOUND %s\n", ans); 391364562Sgshapiro return cp; 391438032Speter } 391538032Speter 391664562Sgshapiro 391764562Sgshapiro /* No match found */ 391838032Speter s->s_namecanon.nc_errno = errno; 391990792Sgshapiro#if NAMED_BIND 392038032Speter s->s_namecanon.nc_herrno = h_errno; 392164562Sgshapiro if (tTd(9, 1)) 392290792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 392364562Sgshapiro switch (h_errno) 392438032Speter { 392564562Sgshapiro case TRY_AGAIN: 392664562Sgshapiro if (UseNameServer) 392764562Sgshapiro { 392864562Sgshapiro CurEnv->e_status = "4.4.3"; 392964562Sgshapiro message("851 %s: Name server timeout", 393064562Sgshapiro shortenstring(name, 33)); 393164562Sgshapiro } 393264562Sgshapiro *statp = EX_TEMPFAIL; 393364562Sgshapiro break; 393464562Sgshapiro 393564562Sgshapiro case HOST_NOT_FOUND: 393664562Sgshapiro case NO_DATA: 393764562Sgshapiro *statp = EX_NOHOST; 393864562Sgshapiro break; 393964562Sgshapiro 394064562Sgshapiro case NO_RECOVERY: 394164562Sgshapiro *statp = EX_SOFTWARE; 394264562Sgshapiro break; 394364562Sgshapiro 394464562Sgshapiro default: 394564562Sgshapiro *statp = EX_UNAVAILABLE; 394664562Sgshapiro break; 394738032Speter } 394890792Sgshapiro#else /* NAMED_BIND */ 394964562Sgshapiro if (tTd(9, 1)) 395090792Sgshapiro sm_dprintf("FAIL\n"); 395164562Sgshapiro *statp = EX_NOHOST; 395290792Sgshapiro#endif /* NAMED_BIND */ 395364562Sgshapiro s->s_namecanon.nc_stat = *statp; 395464562Sgshapiro return NULL; 395538032Speter} 395638032Speter/* 395790792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 395838032Speter** 395938032Speter** Parameters: 396090792Sgshapiro** map -- a pointer to this map. 396190792Sgshapiro** args -- argument string. 396238032Speter** 396338032Speter** Returns: 396490792Sgshapiro** true. 396538032Speter*/ 396638032Speter 396738032Speterbool 396838032Speterhost_map_init(map, args) 396938032Speter MAP *map; 397038032Speter char *args; 397138032Speter{ 397238032Speter register char *p = args; 397338032Speter 397438032Speter for (;;) 397538032Speter { 397638032Speter while (isascii(*p) && isspace(*p)) 397738032Speter p++; 397838032Speter if (*p != '-') 397938032Speter break; 398038032Speter switch (*++p) 398138032Speter { 398238032Speter case 'a': 398338032Speter map->map_app = ++p; 398438032Speter break; 398538032Speter 398638032Speter case 'T': 398738032Speter map->map_tapp = ++p; 398838032Speter break; 398938032Speter 399038032Speter case 'm': 399138032Speter map->map_mflags |= MF_MATCHONLY; 399238032Speter break; 399338032Speter 399438032Speter case 't': 399538032Speter map->map_mflags |= MF_NODEFER; 399638032Speter break; 399764562Sgshapiro 399864562Sgshapiro case 'S': /* only for consistency */ 399964562Sgshapiro map->map_spacesub = *++p; 400064562Sgshapiro break; 400164562Sgshapiro 400264562Sgshapiro case 'D': 400364562Sgshapiro map->map_mflags |= MF_DEFER; 400464562Sgshapiro break; 400590792Sgshapiro 400690792Sgshapiro case 'd': 400790792Sgshapiro { 400890792Sgshapiro char *h; 400990792Sgshapiro 401090792Sgshapiro while (isascii(*++p) && isspace(*p)) 401190792Sgshapiro continue; 401290792Sgshapiro h = strchr(p, ' '); 401390792Sgshapiro if (h != NULL) 401490792Sgshapiro *h = '\0'; 401590792Sgshapiro map->map_timeout = convtime(p, 's'); 401690792Sgshapiro if (h != NULL) 401790792Sgshapiro *h = ' '; 401890792Sgshapiro } 401990792Sgshapiro break; 402090792Sgshapiro 402190792Sgshapiro case 'r': 402290792Sgshapiro while (isascii(*++p) && isspace(*p)) 402390792Sgshapiro continue; 402490792Sgshapiro map->map_retry = atoi(p); 402590792Sgshapiro break; 402638032Speter } 402738032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 402838032Speter p++; 402938032Speter if (*p != '\0') 403038032Speter *p++ = '\0'; 403138032Speter } 403238032Speter if (map->map_app != NULL) 403338032Speter map->map_app = newstr(map->map_app); 403438032Speter if (map->map_tapp != NULL) 403538032Speter map->map_tapp = newstr(map->map_tapp); 403690792Sgshapiro return true; 403738032Speter} 403890792Sgshapiro 403964562Sgshapiro#if NETINET6 404064562Sgshapiro/* 404164562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 404264562Sgshapiro** 404364562Sgshapiro** Parameters: 404464562Sgshapiro** s6a -- a pointer to an in6_addr structure. 404564562Sgshapiro** dst -- buffer to store result in 404664562Sgshapiro** dst_len -- size of dst buffer 404764562Sgshapiro** 404864562Sgshapiro** Returns: 404964562Sgshapiro** A printable version of that structure. 405064562Sgshapiro*/ 405190792Sgshapiro 405264562Sgshapirochar * 405364562Sgshapiroanynet_ntop(s6a, dst, dst_len) 405464562Sgshapiro struct in6_addr *s6a; 405564562Sgshapiro char *dst; 405664562Sgshapiro size_t dst_len; 405764562Sgshapiro{ 405864562Sgshapiro register char *ap; 405964562Sgshapiro 406064562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 406164562Sgshapiro ap = (char *) inet_ntop(AF_INET, 406264562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 406364562Sgshapiro dst, dst_len); 406464562Sgshapiro else 406590792Sgshapiro { 406690792Sgshapiro char *d; 406790792Sgshapiro size_t sz; 406890792Sgshapiro 406990792Sgshapiro /* Save pointer to beginning of string */ 407090792Sgshapiro d = dst; 407190792Sgshapiro 407290792Sgshapiro /* Add IPv6: protocol tag */ 407390792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 407490792Sgshapiro if (sz >= dst_len) 407590792Sgshapiro return NULL; 407690792Sgshapiro dst += sz; 407790792Sgshapiro dst_len -= sz; 407864562Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 407990792Sgshapiro 408090792Sgshapiro /* Restore pointer to beginning of string */ 408190792Sgshapiro if (ap != NULL) 408290792Sgshapiro ap = d; 408390792Sgshapiro } 408464562Sgshapiro return ap; 408564562Sgshapiro} 408690792Sgshapiro 408790792Sgshapiro/* 408890792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 408990792Sgshapiro** 409090792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 409190792Sgshapiro** 409290792Sgshapiro** Parameters: 409390792Sgshapiro** family -- address family 409490792Sgshapiro** src -- string 409590792Sgshapiro** dst -- destination address structure 409690792Sgshapiro** 409790792Sgshapiro** Returns: 409890792Sgshapiro** 1 if the address was valid 409990792Sgshapiro** 0 if the address wasn't parseable 410090792Sgshapiro** -1 if error 410190792Sgshapiro*/ 410290792Sgshapiro 410390792Sgshapiroint 410490792Sgshapiroanynet_pton(family, src, dst) 410590792Sgshapiro int family; 410690792Sgshapiro const char *src; 410790792Sgshapiro void *dst; 410890792Sgshapiro{ 410990792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 411090792Sgshapiro src += 5; 411190792Sgshapiro return inet_pton(family, src, dst); 411290792Sgshapiro} 411364562Sgshapiro#endif /* NETINET6 */ 411490792Sgshapiro/* 411538032Speter** ANYNET_NTOA -- convert a network address to printable form. 411638032Speter** 411738032Speter** Parameters: 411838032Speter** sap -- a pointer to a sockaddr structure. 411938032Speter** 412038032Speter** Returns: 412138032Speter** A printable version of that sockaddr. 412238032Speter*/ 412338032Speter 412438032Speter#ifdef USE_SOCK_STREAM 412538032Speter 412664562Sgshapiro# if NETLINK 412764562Sgshapiro# include <net/if_dl.h> 412864562Sgshapiro# endif /* NETLINK */ 412938032Speter 413038032Speterchar * 413138032Speteranynet_ntoa(sap) 413238032Speter register SOCKADDR *sap; 413338032Speter{ 413438032Speter register char *bp; 413538032Speter register char *ap; 413638032Speter int l; 413738032Speter static char buf[100]; 413838032Speter 413938032Speter /* check for null/zero family */ 414038032Speter if (sap == NULL) 414138032Speter return "NULLADDR"; 414238032Speter if (sap->sa.sa_family == 0) 414338032Speter return "0"; 414438032Speter 414538032Speter switch (sap->sa.sa_family) 414638032Speter { 414764562Sgshapiro# if NETUNIX 414838032Speter case AF_UNIX: 414964562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 415090792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]", 415190792Sgshapiro sap->sunix.sun_path); 415264562Sgshapiro else 415390792Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf); 415438032Speter return buf; 415564562Sgshapiro# endif /* NETUNIX */ 415638032Speter 415764562Sgshapiro# if NETINET 415838032Speter case AF_INET: 415964562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 416064562Sgshapiro# endif /* NETINET */ 416138032Speter 416264562Sgshapiro# if NETINET6 416364562Sgshapiro case AF_INET6: 416464562Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf); 416564562Sgshapiro if (ap != NULL) 416664562Sgshapiro return ap; 416764562Sgshapiro break; 416864562Sgshapiro# endif /* NETINET6 */ 416964562Sgshapiro 417064562Sgshapiro# if NETLINK 417138032Speter case AF_LINK: 417290792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[LINK: %s]", 417390792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 417438032Speter return buf; 417564562Sgshapiro# endif /* NETLINK */ 417638032Speter default: 417738032Speter /* this case is needed when nothing is #defined */ 417838032Speter /* in order to keep the switch syntactically correct */ 417938032Speter break; 418038032Speter } 418138032Speter 418238032Speter /* unknown family -- just dump bytes */ 418390792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 418438032Speter bp = &buf[strlen(buf)]; 418538032Speter ap = sap->sa.sa_data; 418638032Speter for (l = sizeof sap->sa.sa_data; --l >= 0; ) 418738032Speter { 418890792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 418990792Sgshapiro *ap++ & 0377); 419038032Speter bp += 3; 419138032Speter } 419238032Speter *--bp = '\0'; 419338032Speter return buf; 419438032Speter} 419590792Sgshapiro/* 419638032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 419738032Speter** 419838032Speter** Parameters: 419938032Speter** sap -- SOCKADDR pointer 420038032Speter** 420138032Speter** Returns: 420238032Speter** text representation of host name. 420338032Speter** 420438032Speter** Side Effects: 420538032Speter** none. 420638032Speter*/ 420738032Speter 420838032Speterchar * 420938032Speterhostnamebyanyaddr(sap) 421038032Speter register SOCKADDR *sap; 421138032Speter{ 421238032Speter register struct hostent *hp; 421364562Sgshapiro# if NAMED_BIND 421438032Speter int saveretry; 421564562Sgshapiro# endif /* NAMED_BIND */ 421664562Sgshapiro# if NETINET6 421764562Sgshapiro struct in6_addr in6_addr; 421864562Sgshapiro# endif /* NETINET6 */ 421938032Speter 422064562Sgshapiro# if NAMED_BIND 422138032Speter /* shorten name server timeout to avoid higher level timeouts */ 422238032Speter saveretry = _res.retry; 422364562Sgshapiro if (_res.retry * _res.retrans > 20) 422464562Sgshapiro _res.retry = 20 / _res.retrans; 422564562Sgshapiro# endif /* NAMED_BIND */ 422638032Speter 422738032Speter switch (sap->sa.sa_family) 422838032Speter { 422964562Sgshapiro# if NETINET 423038032Speter case AF_INET: 423138032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 423290792Sgshapiro INADDRSZ, AF_INET); 423338032Speter break; 423464562Sgshapiro# endif /* NETINET */ 423538032Speter 423664562Sgshapiro# if NETINET6 423764562Sgshapiro case AF_INET6: 423864562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 423990792Sgshapiro IN6ADDRSZ, AF_INET6); 424064562Sgshapiro break; 424164562Sgshapiro# endif /* NETINET6 */ 424264562Sgshapiro 424364562Sgshapiro# if NETISO 424438032Speter case AF_ISO: 424538032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 424690792Sgshapiro sizeof sap->siso.siso_addr, AF_ISO); 424738032Speter break; 424864562Sgshapiro# endif /* NETISO */ 424938032Speter 425064562Sgshapiro# if NETUNIX 425138032Speter case AF_UNIX: 425238032Speter hp = NULL; 425338032Speter break; 425464562Sgshapiro# endif /* NETUNIX */ 425538032Speter 425638032Speter default: 425790792Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data, 425890792Sgshapiro sap->sa.sa_family); 425938032Speter break; 426038032Speter } 426138032Speter 426264562Sgshapiro# if NAMED_BIND 426338032Speter _res.retry = saveretry; 426464562Sgshapiro# endif /* NAMED_BIND */ 426538032Speter 426664562Sgshapiro# if NETINET || NETINET6 426764562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 426864562Sgshapiro# if NETINET6 426964562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 427064562Sgshapiro# endif /* NETINET6 */ 427164562Sgshapiro# if NETINET 427264562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 427364562Sgshapiro# endif /* NETINET */ 427464562Sgshapiro ) 427571345Sgshapiro { 427671345Sgshapiro char *name; 427771345Sgshapiro 427890792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 427990792Sgshapiro# if NETINET6 428071345Sgshapiro if (name == hp->h_name) 428171345Sgshapiro { 428271345Sgshapiro static char n[MAXNAME + 1]; 428371345Sgshapiro 428471345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 428590792Sgshapiro (void) sm_strlcpy(n, name, sizeof n); 428671345Sgshapiro name = n; 428771345Sgshapiro } 428871345Sgshapiro freehostent(hp); 428990792Sgshapiro# endif /* NETINET6 */ 429071345Sgshapiro return name; 429171345Sgshapiro } 429264562Sgshapiro# endif /* NETINET || NETINET6 */ 429371345Sgshapiro 429490792Sgshapiro# if NETINET6 429571345Sgshapiro if (hp != NULL) 429671345Sgshapiro { 429771345Sgshapiro freehostent(hp); 429871345Sgshapiro hp = NULL; 429971345Sgshapiro } 430090792Sgshapiro# endif /* NETINET6 */ 430171345Sgshapiro 430264562Sgshapiro# if NETUNIX 430364562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 430438032Speter return "localhost"; 430564562Sgshapiro# endif /* NETUNIX */ 430638032Speter { 430738032Speter static char buf[203]; 430838032Speter 430990792Sgshapiro (void) sm_snprintf(buf, sizeof buf, "[%.200s]", 431090792Sgshapiro anynet_ntoa(sap)); 431138032Speter return buf; 431238032Speter } 431338032Speter} 431464562Sgshapiro#endif /* USE_SOCK_STREAM */ 4315