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