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