daemon.c revision 157001
138032Speter/*
2157001Sgshapiro * Copyright (c) 1998-2006 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
16157001SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.665 2006/03/02 19:12:00 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
37157001Sgshapiro#include <sm/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	char		*d_inputfilterlist;
7890792Sgshapiro	struct milter	*d_inputfilters[MAXFILTERS];
7990792Sgshapiro#endif /* MILTER */
80147078Sgshapiro#if _FFR_SS_PER_DAEMON
81147078Sgshapiro	int		d_supersafe;
82147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */
83147078Sgshapiro#if _FFR_DM_PER_DAEMON
84147078Sgshapiro	int		d_dm;	/* DeliveryMode */
85147078Sgshapiro#endif /* _FFR_DM_PER_DAEMON */
8664562Sgshapiro};
8764562Sgshapiro
8864562Sgshapirotypedef struct daemon DAEMON_T;
8964562Sgshapiro
90147078Sgshapiro#define SAFE_NOTSET	(-1)	/* SuperSafe (per daemon) option not set */
91147078Sgshapiro/* see also sendmail.h: SuperSafe values */
92147078Sgshapiro
93141858Sgshapirostatic void		connecttimeout __P((int));
9490792Sgshapirostatic int		opendaemonsocket __P((DAEMON_T *, bool));
9590792Sgshapirostatic unsigned short	setupdaemon __P((SOCKADDR *));
9690792Sgshapirostatic void		getrequests_checkdiskspace __P((ENVELOPE *e));
97141858Sgshapirostatic void		setsockaddroptions __P((char *, DAEMON_T *));
98141858Sgshapirostatic void		printdaemonflags __P((DAEMON_T *));
99141858Sgshapirostatic int		addr_family __P((char *));
100141858Sgshapirostatic int		addrcmp __P((struct hostent *, char *, SOCKADDR *));
101141858Sgshapirostatic void		authtimeout __P((int));
10264562Sgshapiro
10338032Speter/*
10438032Speter**  DAEMON.C -- routines to use when running as a daemon.
10538032Speter**
10638032Speter**	This entire file is highly dependent on the 4.2 BSD
10738032Speter**	interprocess communication primitives.  No attempt has
10838032Speter**	been made to make this file portable to Version 7,
10938032Speter**	Version 6, MPX files, etc.  If you should try such a
11038032Speter**	thing yourself, I recommend chucking the entire file
11138032Speter**	and starting from scratch.  Basic semantics are:
11238032Speter**
11338032Speter**	getrequests(e)
11438032Speter**		Opens a port and initiates a connection.
11538032Speter**		Returns in a child.  Must set InChannel and
11638032Speter**		OutChannel appropriately.
11738032Speter**	clrdaemon()
11838032Speter**		Close any open files associated with getting
11938032Speter**		the connection; this is used when running the queue,
12038032Speter**		etc., to avoid having extra file descriptors during
12138032Speter**		the queue run and to avoid confusing the network
12238032Speter**		code (if it cares).
12390792Sgshapiro**	makeconnection(host, port, mci, e, enough)
12438032Speter**		Make a connection to the named host on the given
12590792Sgshapiro**		port. Returns zero on success, else an exit status
12690792Sgshapiro**		describing the error.
12738032Speter**	host_map_lookup(map, hbuf, avp, pstat)
12838032Speter**		Convert the entry in hbuf into a canonical form.
12938032Speter*/
13064562Sgshapiro
13164562Sgshapirostatic DAEMON_T	Daemons[MAXDAEMONS];
13290792Sgshapirostatic int	NDaemons = 0;			/* actual number of daemons */
13364562Sgshapiro
13490792Sgshapirostatic time_t	NextDiskSpaceCheck = 0;
13564562Sgshapiro
13690792Sgshapiro/*
13738032Speter**  GETREQUESTS -- open mail IPC port and get requests.
13838032Speter**
13938032Speter**	Parameters:
14038032Speter**		e -- the current envelope.
14138032Speter**
14238032Speter**	Returns:
14364562Sgshapiro**		pointer to flags.
14438032Speter**
14538032Speter**	Side Effects:
14638032Speter**		Waits until some interesting activity occurs.  When
14738032Speter**		it does, a child is created to process it, and the
14838032Speter**		parent waits for completion.  Return from this
14938032Speter**		routine is always in the child.  The file pointers
15038032Speter**		"InChannel" and "OutChannel" should be set to point
15138032Speter**		to the communication channel.
15290792Sgshapiro**		May restart persistent queue runners if they have ended
15390792Sgshapiro**		for some reason.
15438032Speter*/
15538032Speter
15664562SgshapiroBITMAP256 *
15738032Spetergetrequests(e)
15838032Speter	ENVELOPE *e;
15938032Speter{
16038032Speter	int t;
16164562Sgshapiro	int idx, curdaemon = -1;
16264562Sgshapiro	int i, olddaemon = 0;
16390792Sgshapiro#if XDEBUG
16438032Speter	bool j_has_dot;
16590792Sgshapiro#endif /* XDEBUG */
16642575Speter	char status[MAXLINE];
16764562Sgshapiro	SOCKADDR sa;
16864562Sgshapiro	SOCKADDR_LEN_T len = sizeof sa;
16994334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA
17094334Sgshapiro	time_t lastrun;
17194334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */
17264562Sgshapiro# if NETUNIX
17342575Speter	extern int ControlSocket;
17464562Sgshapiro# endif /* NETUNIX */
17564562Sgshapiro	extern ENVELOPE BlankEnvelope;
17690792Sgshapiro	extern bool refuseconnections __P((char *, ENVELOPE *, int, bool));
17738032Speter
17838032Speter
179125820Sgshapiro	/* initialize data for function that generates queue ids */
180125820Sgshapiro	init_qid_alg();
18190792Sgshapiro	for (idx = 0; idx < NDaemons; idx++)
18238032Speter	{
18364562Sgshapiro		Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
18490792Sgshapiro		Daemons[idx].d_firsttime = true;
18564562Sgshapiro		Daemons[idx].d_refuse_connections_until = (time_t) 0;
18638032Speter	}
18771345Sgshapiro
18838032Speter	/*
18938032Speter	**  Try to actually open the connection.
19038032Speter	*/
19138032Speter
19238032Speter	if (tTd(15, 1))
19364562Sgshapiro	{
19490792Sgshapiro		for (idx = 0; idx < NDaemons; idx++)
19571345Sgshapiro		{
19690792Sgshapiro			sm_dprintf("getrequests: daemon %s: port %d\n",
19790792Sgshapiro				   Daemons[idx].d_name,
19890792Sgshapiro				   ntohs(Daemons[idx].d_port));
19971345Sgshapiro		}
20064562Sgshapiro	}
20138032Speter
20238032Speter	/* get a socket for the SMTP connection */
20390792Sgshapiro	for (idx = 0; idx < NDaemons; idx++)
20490792Sgshapiro		Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true);
20538032Speter
20642575Speter	if (opencontrolsocket() < 0)
20742575Speter		sm_syslog(LOG_WARNING, NOQID,
20843730Speter			  "daemon could not open control socket %s: %s",
20990792Sgshapiro			  ControlSocketName, sm_errstring(errno));
21042575Speter
21190792Sgshapiro	/* If there are any queue runners released reapchild() co-ord's */
21290792Sgshapiro	(void) sm_signal(SIGCHLD, reapchild);
21338032Speter
21490792Sgshapiro	/* write the pid to file, command line args to syslog */
21564562Sgshapiro	log_sendmail_pid(e);
21638032Speter
21790792Sgshapiro#if XDEBUG
21838032Speter	{
21938032Speter		char jbuf[MAXHOSTNAMELEN];
22038032Speter
22138032Speter		expand("\201j", jbuf, sizeof jbuf, e);
22238032Speter		j_has_dot = strchr(jbuf, '.') != NULL;
22338032Speter	}
22490792Sgshapiro#endif /* XDEBUG */
22538032Speter
22642575Speter	/* Add parent process as first item */
227132943Sgshapiro	proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL);
22842575Speter
22938032Speter	if (tTd(15, 1))
23064562Sgshapiro	{
23190792Sgshapiro		for (idx = 0; idx < NDaemons; idx++)
23290792Sgshapiro			sm_dprintf("getrequests: daemon %s: %d\n",
23364562Sgshapiro				Daemons[idx].d_name,
23464562Sgshapiro				Daemons[idx].d_socket);
23564562Sgshapiro	}
23638032Speter
23738032Speter	for (;;)
23838032Speter	{
23938032Speter		register pid_t pid;
24038032Speter		auto SOCKADDR_LEN_T lotherend;
24190792Sgshapiro		bool timedout = false;
24290792Sgshapiro		bool control = false;
24364562Sgshapiro		int save_errno;
24438032Speter		int pipefd[2];
24590792Sgshapiro		time_t now;
24690792Sgshapiro#if STARTTLS
24766494Sgshapiro		long seed;
24890792Sgshapiro#endif /* STARTTLS */
24938032Speter
25038032Speter		/* see if we are rejecting connections */
25190792Sgshapiro		(void) sm_blocksignal(SIGALRM);
252120256Sgshapiro		CHECK_RESTART;
25364562Sgshapiro
25490792Sgshapiro		for (idx = 0; idx < NDaemons; idx++)
25571345Sgshapiro		{
25690792Sgshapiro			/*
25790792Sgshapiro			**  XXX do this call outside the loop?
25890792Sgshapiro			**	no: refuse_connections may sleep().
25990792Sgshapiro			*/
26071345Sgshapiro
26190792Sgshapiro			now = curtime();
26290792Sgshapiro			if (now < Daemons[idx].d_refuse_connections_until)
26364562Sgshapiro				continue;
26490792Sgshapiro			if (bitnset(D_DISABLE, Daemons[idx].d_flags))
26590792Sgshapiro				continue;
26690792Sgshapiro			if (refuseconnections(Daemons[idx].d_name, e, idx,
26790792Sgshapiro					      curdaemon == idx))
26838032Speter			{
26964562Sgshapiro				if (Daemons[idx].d_socket >= 0)
27042575Speter				{
27171345Sgshapiro					/* close socket so peer fails quickly */
27271345Sgshapiro					(void) close(Daemons[idx].d_socket);
27371345Sgshapiro					Daemons[idx].d_socket = -1;
27442575Speter				}
27542575Speter
27642575Speter				/* refuse connections for next 15 seconds */
27790792Sgshapiro				Daemons[idx].d_refuse_connections_until = now + 15;
27838032Speter			}
27964562Sgshapiro			else if (Daemons[idx].d_socket < 0 ||
28064562Sgshapiro				 Daemons[idx].d_firsttime)
28142575Speter			{
28290792Sgshapiro				if (!Daemons[idx].d_firsttime && LogLevel > 8)
28371345Sgshapiro					sm_syslog(LOG_INFO, NOQID,
28471345Sgshapiro						"accepting connections again for daemon %s",
28571345Sgshapiro						Daemons[idx].d_name);
28664562Sgshapiro
28771345Sgshapiro				/* arrange to (re)open the socket if needed */
28890792Sgshapiro				(void) opendaemonsocket(&Daemons[idx], false);
28990792Sgshapiro				Daemons[idx].d_firsttime = false;
29042575Speter			}
29138032Speter		}
29238032Speter
29377349Sgshapiro		/* May have been sleeping above, check again */
294120256Sgshapiro		CHECK_RESTART;
295132943Sgshapiro
29690792Sgshapiro		getrequests_checkdiskspace(e);
29771345Sgshapiro
29890792Sgshapiro#if XDEBUG
29938032Speter		/* check for disaster */
30038032Speter		{
30138032Speter			char jbuf[MAXHOSTNAMELEN];
30238032Speter
30338032Speter			expand("\201j", jbuf, sizeof jbuf, e);
30438032Speter			if (!wordinclass(jbuf, 'w'))
30538032Speter			{
30638032Speter				dumpstate("daemon lost $j");
30738032Speter				sm_syslog(LOG_ALERT, NOQID,
30864562Sgshapiro					  "daemon process doesn't have $j in $=w; see syslog");
30938032Speter				abort();
31038032Speter			}
31138032Speter			else if (j_has_dot && strchr(jbuf, '.') == NULL)
31238032Speter			{
31338032Speter				dumpstate("daemon $j lost dot");
31438032Speter				sm_syslog(LOG_ALERT, NOQID,
31564562Sgshapiro					  "daemon process $j lost dot; see syslog");
31638032Speter				abort();
31738032Speter			}
31838032Speter		}
31990792Sgshapiro#endif /* XDEBUG */
32038032Speter
32190792Sgshapiro#if 0
32238032Speter		/*
32338032Speter		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
32438032Speter		**  fix the SVr4 problem.  But it seems to have gone away,
32538032Speter		**  so is it worth doing this?
32638032Speter		*/
32738032Speter
32842575Speter		if (DaemonSocket >= 0 &&
32990792Sgshapiro		    SetNonBlocking(DaemonSocket, false) < 0)
33038032Speter			log an error here;
33190792Sgshapiro#endif /* 0 */
33290792Sgshapiro		(void) sm_releasesignal(SIGALRM);
33364562Sgshapiro
33438032Speter		for (;;)
33538032Speter		{
33690792Sgshapiro			bool setproc = false;
33742575Speter			int highest = -1;
33838032Speter			fd_set readfds;
33938032Speter			struct timeval timeout;
34038032Speter
341120256Sgshapiro			CHECK_RESTART;
34238032Speter			FD_ZERO(&readfds);
34390792Sgshapiro			for (idx = 0; idx < NDaemons; idx++)
34442575Speter			{
34564562Sgshapiro				/* wait for a connection */
34664562Sgshapiro				if (Daemons[idx].d_socket >= 0)
34764562Sgshapiro				{
34871345Sgshapiro					if (!setproc &&
34971345Sgshapiro					    !bitnset(D_ETRNONLY,
35071345Sgshapiro						     Daemons[idx].d_flags))
35164562Sgshapiro					{
35290792Sgshapiro						sm_setproctitle(true, e,
35364562Sgshapiro								"accepting connections");
35490792Sgshapiro						setproc = true;
35564562Sgshapiro					}
35664562Sgshapiro					if (Daemons[idx].d_socket > highest)
35764562Sgshapiro						highest = Daemons[idx].d_socket;
35890792Sgshapiro					SM_FD_SET(Daemons[idx].d_socket,
35990792Sgshapiro						  &readfds);
36064562Sgshapiro				}
36142575Speter			}
36264562Sgshapiro
36390792Sgshapiro#if NETUNIX
36442575Speter			if (ControlSocket >= 0)
36542575Speter			{
36642575Speter				if (ControlSocket > highest)
36742575Speter					highest = ControlSocket;
36890792Sgshapiro				SM_FD_SET(ControlSocket, &readfds);
36942575Speter			}
37090792Sgshapiro#endif /* NETUNIX */
37164562Sgshapiro
37277349Sgshapiro			timeout.tv_sec = 5;
37338032Speter			timeout.tv_usec = 0;
37438032Speter
37542575Speter			t = select(highest + 1, FDSET_CAST &readfds,
37664562Sgshapiro				   NULL, NULL, &timeout);
37742575Speter
37877349Sgshapiro			/* Did someone signal while waiting? */
379120256Sgshapiro			CHECK_RESTART;
38071345Sgshapiro
38190792Sgshapiro			curdaemon = -1;
38290792Sgshapiro			if (doqueuerun())
38394334Sgshapiro			{
38490792Sgshapiro				(void) runqueue(true, false, false, false);
38594334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA
38694334Sgshapiro				lastrun = now;
38794334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */
38894334Sgshapiro			}
38994334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA
390157001Sgshapiro			else if (CheckQueueRunners > 0 && QueueIntvl > 0 &&
391157001Sgshapiro				 lastrun + QueueIntvl + CheckQueueRunners < now)
39294334Sgshapiro			{
39371345Sgshapiro
39494334Sgshapiro				/*
39594334Sgshapiro				**  set lastrun unconditionally to avoid
39694334Sgshapiro				**  calling checkqueuerunner() all the time.
39794334Sgshapiro				**  That's also why we currently ignore the
39894334Sgshapiro				**  result of the function call.
39994334Sgshapiro				*/
40094334Sgshapiro
40194334Sgshapiro				(void) checkqueuerunner();
40294334Sgshapiro				lastrun = now;
40394334Sgshapiro			}
40494334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */
40594334Sgshapiro
40642575Speter			if (t <= 0)
40742575Speter			{
40890792Sgshapiro				timedout = true;
40942575Speter				break;
41042575Speter			}
41138032Speter
41290792Sgshapiro			control = false;
41338032Speter			errno = 0;
41464562Sgshapiro
41564562Sgshapiro			/* look "round-robin" for an active socket */
41690792Sgshapiro			if ((idx = olddaemon + 1) >= NDaemons)
41764562Sgshapiro				idx = 0;
41890792Sgshapiro			for (i = 0; i < NDaemons; i++)
41942575Speter			{
42064562Sgshapiro				if (Daemons[idx].d_socket >= 0 &&
42190792Sgshapiro				    SM_FD_ISSET(Daemons[idx].d_socket,
42290792Sgshapiro						&readfds))
42364562Sgshapiro				{
42464562Sgshapiro					lotherend = Daemons[idx].d_socksize;
42573188Sgshapiro					memset(&RealHostAddr, '\0',
42673188Sgshapiro					       sizeof RealHostAddr);
42764562Sgshapiro					t = accept(Daemons[idx].d_socket,
42864562Sgshapiro						   (struct sockaddr *)&RealHostAddr,
42964562Sgshapiro						   &lotherend);
43073188Sgshapiro
43173188Sgshapiro					/*
43273188Sgshapiro					**  If remote side closes before
43373188Sgshapiro					**  accept() finishes, sockaddr
43473188Sgshapiro					**  might not be fully filled in.
43573188Sgshapiro					*/
43673188Sgshapiro
43773188Sgshapiro					if (t >= 0 &&
43873188Sgshapiro					    (lotherend == 0 ||
43973188Sgshapiro# ifdef BSD4_4_SOCKADDR
44073188Sgshapiro					     RealHostAddr.sa.sa_len == 0 ||
44173188Sgshapiro# endif /* BSD4_4_SOCKADDR */
44273188Sgshapiro					     RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family))
44373188Sgshapiro					{
44473188Sgshapiro						(void) close(t);
44573188Sgshapiro						t = -1;
44673188Sgshapiro						errno = EINVAL;
44773188Sgshapiro					}
44864562Sgshapiro					olddaemon = curdaemon = idx;
44964562Sgshapiro					break;
45064562Sgshapiro				}
45190792Sgshapiro				if (++idx >= NDaemons)
45264562Sgshapiro					idx = 0;
45342575Speter			}
45490792Sgshapiro#if NETUNIX
45564562Sgshapiro			if (curdaemon == -1 && ControlSocket >= 0 &&
45690792Sgshapiro			    SM_FD_ISSET(ControlSocket, &readfds))
45742575Speter			{
45842575Speter				struct sockaddr_un sa_un;
45942575Speter
46042575Speter				lotherend = sizeof sa_un;
46173188Sgshapiro				memset(&sa_un, '\0', sizeof sa_un);
46242575Speter				t = accept(ControlSocket,
46342575Speter					   (struct sockaddr *)&sa_un,
46442575Speter					   &lotherend);
46573188Sgshapiro
46673188Sgshapiro				/*
46773188Sgshapiro				**  If remote side closes before
46873188Sgshapiro				**  accept() finishes, sockaddr
46973188Sgshapiro				**  might not be fully filled in.
47073188Sgshapiro				*/
47173188Sgshapiro
47273188Sgshapiro				if (t >= 0 &&
47373188Sgshapiro				    (lotherend == 0 ||
47473188Sgshapiro# ifdef BSD4_4_SOCKADDR
47573188Sgshapiro				     sa_un.sun_len == 0 ||
47673188Sgshapiro# endif /* BSD4_4_SOCKADDR */
47773188Sgshapiro				     sa_un.sun_family != AF_UNIX))
47873188Sgshapiro				{
47973188Sgshapiro					(void) close(t);
48073188Sgshapiro					t = -1;
48173188Sgshapiro					errno = EINVAL;
48273188Sgshapiro				}
48373188Sgshapiro				if (t >= 0)
48490792Sgshapiro					control = true;
48542575Speter			}
48690792Sgshapiro#else /* NETUNIX */
48771345Sgshapiro			if (curdaemon == -1)
48871345Sgshapiro			{
48971345Sgshapiro				/* No daemon to service */
49071345Sgshapiro				continue;
49171345Sgshapiro			}
49290792Sgshapiro#endif /* NETUNIX */
49338032Speter			if (t >= 0 || errno != EINTR)
49438032Speter				break;
49538032Speter		}
49642575Speter		if (timedout)
49742575Speter		{
49890792Sgshapiro			timedout = false;
49942575Speter			continue;
50042575Speter		}
50164562Sgshapiro		save_errno = errno;
50290792Sgshapiro		(void) sm_blocksignal(SIGALRM);
50338032Speter		if (t < 0)
50438032Speter		{
50564562Sgshapiro			errno = save_errno;
506132943Sgshapiro
507132943Sgshapiro			/* let's ignore these temporary errors */
508132943Sgshapiro			if (save_errno == EINTR
509132943Sgshapiro#ifdef EAGAIN
510132943Sgshapiro			    || save_errno == EAGAIN
511132943Sgshapiro#endif /* EAGAIN */
512132943Sgshapiro#ifdef ECONNABORTED
513132943Sgshapiro			    || save_errno == ECONNABORTED
514132943Sgshapiro#endif /* ECONNABORTED */
515132943Sgshapiro#ifdef EWOULDBLOCK
516132943Sgshapiro			    || save_errno == EWOULDBLOCK
517132943Sgshapiro#endif /* EWOULDBLOCK */
518132943Sgshapiro			   )
519132943Sgshapiro				continue;
520132943Sgshapiro
52138032Speter			syserr("getrequests: accept");
52238032Speter
52338032Speter			/* arrange to re-open the socket next time around */
52464562Sgshapiro			(void) close(Daemons[curdaemon].d_socket);
52564562Sgshapiro			Daemons[curdaemon].d_socket = -1;
52690792Sgshapiro#if SO_REUSEADDR_IS_BROKEN
52764562Sgshapiro			/*
52864562Sgshapiro			**  Give time for bound socket to be released.
52964562Sgshapiro			**  This creates a denial-of-service if you can
53064562Sgshapiro			**  force accept() to fail on affected systems.
53164562Sgshapiro			*/
53264562Sgshapiro
53390792Sgshapiro			Daemons[curdaemon].d_refuse_connections_until = curtime() + 15;
53490792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */
53538032Speter			continue;
53638032Speter		}
53738032Speter
53864562Sgshapiro		if (!control)
53964562Sgshapiro		{
54064562Sgshapiro			/* set some daemon related macros */
54164562Sgshapiro			switch (Daemons[curdaemon].d_addr.sa.sa_family)
54264562Sgshapiro			{
54364562Sgshapiro			  case AF_UNSPEC:
54490792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
54590792Sgshapiro					macid("{daemon_family}"), "unspec");
54664562Sgshapiro				break;
54790792Sgshapiro#if _FFR_DAEMON_NETUNIX
54890792Sgshapiro# if NETUNIX
54990792Sgshapiro			  case AF_UNIX:
55090792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
55190792Sgshapiro					macid("{daemon_family}"), "local");
55290792Sgshapiro				break;
55390792Sgshapiro# endif /* NETUNIX */
55490792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */
55590792Sgshapiro#if NETINET
55664562Sgshapiro			  case AF_INET:
55790792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
55890792Sgshapiro					macid("{daemon_family}"), "inet");
55964562Sgshapiro				break;
56090792Sgshapiro#endif /* NETINET */
56190792Sgshapiro#if NETINET6
56264562Sgshapiro			  case AF_INET6:
56390792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
56490792Sgshapiro					macid("{daemon_family}"), "inet6");
56564562Sgshapiro				break;
56690792Sgshapiro#endif /* NETINET6 */
56790792Sgshapiro#if NETISO
56864562Sgshapiro			  case AF_ISO:
56990792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
57090792Sgshapiro					macid("{daemon_family}"), "iso");
57164562Sgshapiro				break;
57290792Sgshapiro#endif /* NETISO */
57390792Sgshapiro#if NETNS
57464562Sgshapiro			  case AF_NS:
57590792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
57690792Sgshapiro					macid("{daemon_family}"), "ns");
57764562Sgshapiro				break;
57890792Sgshapiro#endif /* NETNS */
57990792Sgshapiro#if NETX25
58064562Sgshapiro			  case AF_CCITT:
58190792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
58290792Sgshapiro					macid("{daemon_family}"), "x.25");
58364562Sgshapiro				break;
58490792Sgshapiro#endif /* NETX25 */
58564562Sgshapiro			}
58690792Sgshapiro			macdefine(&BlankEnvelope.e_macro, A_PERM,
58790792Sgshapiro				macid("{daemon_name}"),
58890792Sgshapiro				Daemons[curdaemon].d_name);
58964562Sgshapiro			if (Daemons[curdaemon].d_mflags != NULL)
59090792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
59190792Sgshapiro					macid("{daemon_flags}"),
59290792Sgshapiro					Daemons[curdaemon].d_mflags);
59364562Sgshapiro			else
59490792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
59590792Sgshapiro					macid("{daemon_flags}"), "");
59664562Sgshapiro		}
59764562Sgshapiro
59838032Speter		/*
599132943Sgshapiro		**  If connection rate is exceeded here, connection shall be
600132943Sgshapiro		**  refused later by a new call after fork() by the
601132943Sgshapiro		**  validate_connection() function. Closing the connection
602132943Sgshapiro		**  at this point violates RFC 2821.
603132943Sgshapiro		**  Do NOT remove this call, its side effects are needed.
604132943Sgshapiro		*/
605132943Sgshapiro
606132943Sgshapiro		connection_rate_check(&RealHostAddr, NULL);
607132943Sgshapiro
608132943Sgshapiro		/*
60938032Speter		**  Create a subprocess to process the mail.
61038032Speter		*/
61138032Speter
61238032Speter		if (tTd(15, 2))
61390792Sgshapiro			sm_dprintf("getrequests: forking (fd = %d)\n", t);
61438032Speter
61538032Speter		/*
61690792Sgshapiro		**  Advance state of PRNG.
61790792Sgshapiro		**  This is necessary because otherwise all child processes
61864562Sgshapiro		**  will produce the same PRN sequence and hence the selection
61964562Sgshapiro		**  of a queue directory (and other things, e.g., MX selection)
62064562Sgshapiro		**  are not "really" random.
62164562Sgshapiro		*/
62290792Sgshapiro#if STARTTLS
62390792Sgshapiro		/* XXX get some better "random" data? */
62466494Sgshapiro		seed = get_random();
62590792Sgshapiro		RAND_seed((void *) &NextDiskSpaceCheck,
62690792Sgshapiro			  sizeof NextDiskSpaceCheck);
62790792Sgshapiro		RAND_seed((void *) &now, sizeof now);
62866494Sgshapiro		RAND_seed((void *) &seed, sizeof seed);
62990792Sgshapiro#else /* STARTTLS */
63064562Sgshapiro		(void) get_random();
63190792Sgshapiro#endif /* STARTTLS */
63264562Sgshapiro
63390792Sgshapiro#if NAMED_BIND
63464562Sgshapiro		/*
635132943Sgshapiro		**  Update MX records for FallbackMX.
63690792Sgshapiro		**  Let's hope this is fast otherwise we screw up the
63790792Sgshapiro		**  response time.
63890792Sgshapiro		*/
63990792Sgshapiro
640132943Sgshapiro		if (FallbackMX != NULL)
641132943Sgshapiro			(void) getfallbackmxrr(FallbackMX);
64290792Sgshapiro#endif /* NAMED_BIND */
64390792Sgshapiro
644110560Sgshapiro		if (tTd(93, 100))
645110560Sgshapiro		{
646110560Sgshapiro			/* don't fork, handle connection in this process */
647110560Sgshapiro			pid = 0;
64838032Speter			pipefd[0] = pipefd[1] = -1;
649110560Sgshapiro		}
650110560Sgshapiro		else
651110560Sgshapiro		{
652110560Sgshapiro			/*
653110560Sgshapiro			**  Create a pipe to keep the child from writing to
654110560Sgshapiro			**  the socket until after the parent has closed
655110560Sgshapiro			**  it.  Otherwise the parent may hang if the child
656110560Sgshapiro			**  has closed it first.
657110560Sgshapiro			*/
65838032Speter
659110560Sgshapiro			if (pipe(pipefd) < 0)
660110560Sgshapiro				pipefd[0] = pipefd[1] = -1;
661110560Sgshapiro
662110560Sgshapiro			(void) sm_blocksignal(SIGCHLD);
663110560Sgshapiro			pid = fork();
664110560Sgshapiro			if (pid < 0)
66538032Speter			{
666110560Sgshapiro				syserr("daemon: cannot fork");
667110560Sgshapiro				if (pipefd[0] != -1)
668110560Sgshapiro				{
669110560Sgshapiro					(void) close(pipefd[0]);
670110560Sgshapiro					(void) close(pipefd[1]);
671110560Sgshapiro				}
672110560Sgshapiro				(void) sm_releasesignal(SIGCHLD);
673110560Sgshapiro				(void) sleep(10);
674110560Sgshapiro				(void) close(t);
675110560Sgshapiro				continue;
67638032Speter			}
67738032Speter		}
67890792Sgshapiro
67938032Speter		if (pid == 0)
68038032Speter		{
68138032Speter			char *p;
68290792Sgshapiro			SM_FILE_T *inchannel, *outchannel = NULL;
68338032Speter
68438032Speter			/*
68538032Speter			**  CHILD -- return to caller.
68638032Speter			**	Collect verified idea of sending host.
68738032Speter			**	Verify calling user id if possible here.
68838032Speter			*/
68938032Speter
69077349Sgshapiro			/* Reset global flags */
69177349Sgshapiro			RestartRequest = NULL;
69290792Sgshapiro			RestartWorkGroup = false;
69377349Sgshapiro			ShutdownRequest = NULL;
69477349Sgshapiro			PendingSignal = 0;
69590792Sgshapiro			CurrentPid = getpid();
696132943Sgshapiro			close_sendmail_pid();
69777349Sgshapiro
69890792Sgshapiro			(void) sm_releasesignal(SIGALRM);
69990792Sgshapiro			(void) sm_releasesignal(SIGCHLD);
70090792Sgshapiro			(void) sm_signal(SIGCHLD, SIG_DFL);
70190792Sgshapiro			(void) sm_signal(SIGHUP, SIG_DFL);
70290792Sgshapiro			(void) sm_signal(SIGTERM, intsig);
70377349Sgshapiro
70490792Sgshapiro			/* turn on profiling */
70590792Sgshapiro			/* SM_PROF(0); */
70690792Sgshapiro
70790792Sgshapiro			/*
70890792Sgshapiro			**  Initialize exception stack and default exception
70990792Sgshapiro			**  handler for child process.
71090792Sgshapiro			*/
71190792Sgshapiro
71290792Sgshapiro			sm_exc_newthread(fatal_error);
71390792Sgshapiro
71464562Sgshapiro			if (!control)
71564562Sgshapiro			{
71690792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_TEMP,
71790792Sgshapiro					macid("{daemon_addr}"),
71890792Sgshapiro					anynet_ntoa(&Daemons[curdaemon].d_addr));
71990792Sgshapiro				(void) sm_snprintf(status, sizeof status, "%d",
72064562Sgshapiro						ntohs(Daemons[curdaemon].d_port));
72190792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_TEMP,
72290792Sgshapiro					macid("{daemon_port}"), status);
72364562Sgshapiro			}
72464562Sgshapiro
72590792Sgshapiro			for (idx = 0; idx < NDaemons; idx++)
72664562Sgshapiro			{
72764562Sgshapiro				if (Daemons[idx].d_socket >= 0)
72864562Sgshapiro					(void) close(Daemons[idx].d_socket);
72980785Sgshapiro				Daemons[idx].d_socket = -1;
73064562Sgshapiro			}
73142575Speter			clrcontrol();
73238032Speter
73364562Sgshapiro			/* Avoid SMTP daemon actions if control command */
73464562Sgshapiro			if (control)
73564562Sgshapiro			{
73664562Sgshapiro				/* Add control socket process */
73790792Sgshapiro				proc_list_add(CurrentPid,
73890792Sgshapiro					      "console socket child",
739132943Sgshapiro					      PROC_CONTROL_CHILD, 0, -1, NULL);
74064562Sgshapiro			}
74164562Sgshapiro			else
74264562Sgshapiro			{
74364562Sgshapiro				proc_list_clear();
74442575Speter
74590792Sgshapiro				/* clean up background delivery children */
74690792Sgshapiro				(void) sm_signal(SIGCHLD, reapchild);
74790792Sgshapiro
74864562Sgshapiro				/* Add parent process as first child item */
74990792Sgshapiro				proc_list_add(CurrentPid, "daemon child",
750132943Sgshapiro					      PROC_DAEMON_CHILD, 0, -1, NULL);
75138032Speter
75264562Sgshapiro				/* don't schedule queue runs if ETRN */
75364562Sgshapiro				QueueIntvl = 0;
754147078Sgshapiro#if _FFR_SS_PER_DAEMON
755147078Sgshapiro				if (Daemons[curdaemon].d_supersafe !=
756147078Sgshapiro				    SAFE_NOTSET)
757147078Sgshapiro					SuperSafe = Daemons[curdaemon].d_supersafe;
758147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */
759147078Sgshapiro#if _FFR_DM_PER_DAEMON
760147078Sgshapiro				if (Daemons[curdaemon].d_dm != DM_NOTSET)
761147078Sgshapiro					set_delivery_mode(
762147078Sgshapiro						Daemons[curdaemon].d_dm, e);
763147078Sgshapiro#endif /* _FFR_DM_PER_DAEMON */
76438032Speter
76590792Sgshapiro				sm_setproctitle(true, e, "startup with %s",
76664562Sgshapiro						anynet_ntoa(&RealHostAddr));
76764562Sgshapiro			}
76864562Sgshapiro
76938032Speter			if (pipefd[0] != -1)
77038032Speter			{
77138032Speter				auto char c;
77238032Speter
77338032Speter				/*
77438032Speter				**  Wait for the parent to close the write end
77538032Speter				**  of the pipe, which we will see as an EOF.
77638032Speter				**  This guarantees that we won't write to the
77738032Speter				**  socket until after the parent has closed
77838032Speter				**  the pipe.
77938032Speter				*/
78038032Speter
78138032Speter				/* close the write end of the pipe */
78238032Speter				(void) close(pipefd[1]);
78338032Speter
78438032Speter				/* we shouldn't be interrupted, but ... */
78538032Speter				while (read(pipefd[0], &c, 1) < 0 &&
78638032Speter				       errno == EINTR)
78738032Speter					continue;
78838032Speter				(void) close(pipefd[0]);
78938032Speter			}
79038032Speter
79164562Sgshapiro			/* control socket processing */
79264562Sgshapiro			if (control)
79364562Sgshapiro			{
79464562Sgshapiro				control_command(t, e);
79564562Sgshapiro				/* NOTREACHED */
79664562Sgshapiro				exit(EX_SOFTWARE);
79764562Sgshapiro			}
79864562Sgshapiro
79938032Speter			/* determine host name */
80038032Speter			p = hostnamebyanyaddr(&RealHostAddr);
80190792Sgshapiro			if (strlen(p) > MAXNAME) /* XXX  - 1 ? */
80238032Speter				p[MAXNAME] = '\0';
80338032Speter			RealHostName = newstr(p);
80464562Sgshapiro			if (RealHostName[0] == '[')
80564562Sgshapiro			{
80690792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
80790792Sgshapiro					macid("{client_resolve}"),
80890792Sgshapiro					h_errno == TRY_AGAIN ? "TEMP" : "FAIL");
80964562Sgshapiro			}
81064562Sgshapiro			else
811132943Sgshapiro			{
81290792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
813132943Sgshapiro					  macid("{client_resolve}"), "OK");
814132943Sgshapiro			}
81590792Sgshapiro			sm_setproctitle(true, e, "startup with %s", p);
81694334Sgshapiro			markstats(e, NULL, STATS_CONNECT);
81738032Speter
81890792Sgshapiro			if ((inchannel = sm_io_open(SmFtStdiofd,
81990792Sgshapiro						    SM_TIME_DEFAULT,
82090792Sgshapiro						    (void *) &t,
821132943Sgshapiro						    SM_IO_RDONLY_B,
82290792Sgshapiro						    NULL)) == NULL ||
82338032Speter			    (t = dup(t)) < 0 ||
82490792Sgshapiro			    (outchannel = sm_io_open(SmFtStdiofd,
82590792Sgshapiro						     SM_TIME_DEFAULT,
82690792Sgshapiro						     (void *) &t,
827132943Sgshapiro						     SM_IO_WRONLY_B,
82890792Sgshapiro						     NULL)) == NULL)
82938032Speter			{
83090792Sgshapiro				syserr("cannot open SMTP server channel, fd=%d",
83190792Sgshapiro					t);
83290792Sgshapiro				finis(false, true, EX_OK);
83338032Speter			}
83490792Sgshapiro			sm_io_automode(inchannel, outchannel);
83538032Speter
83638032Speter			InChannel = inchannel;
83738032Speter			OutChannel = outchannel;
83890792Sgshapiro			DisConnected = false;
83938032Speter
84090792Sgshapiro#if XLA
84138032Speter			if (!xla_host_ok(RealHostName))
84238032Speter			{
84364562Sgshapiro				message("421 4.4.5 Too many SMTP sessions for this host");
84490792Sgshapiro				finis(false, true, EX_OK);
84538032Speter			}
84690792Sgshapiro#endif /* XLA */
84764562Sgshapiro			/* find out name for interface of connection */
84890792Sgshapiro			if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
84990792Sgshapiro						      NULL), &sa.sa, &len) == 0)
85064562Sgshapiro			{
85164562Sgshapiro				p = hostnamebyanyaddr(&sa);
85264562Sgshapiro				if (tTd(15, 9))
85390792Sgshapiro					sm_dprintf("getreq: got name %s\n", p);
85490792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_TEMP,
85590792Sgshapiro					macid("{if_name}"), p);
85664562Sgshapiro
85790792Sgshapiro				/*
85890792Sgshapiro				**  Do this only if it is not the loopback
85990792Sgshapiro				**  interface.
86090792Sgshapiro				*/
86190792Sgshapiro
86264562Sgshapiro				if (!isloopback(sa))
86364562Sgshapiro				{
86490792Sgshapiro					char *addr;
86590792Sgshapiro					char family[5];
86690792Sgshapiro
86790792Sgshapiro					addr = anynet_ntoa(&sa);
86890792Sgshapiro					(void) sm_snprintf(family,
86990792Sgshapiro						sizeof(family),
87090792Sgshapiro						"%d", sa.sa.sa_family);
87190792Sgshapiro					macdefine(&BlankEnvelope.e_macro,
87290792Sgshapiro						A_TEMP,
87390792Sgshapiro						macid("{if_addr}"), addr);
87490792Sgshapiro					macdefine(&BlankEnvelope.e_macro,
87590792Sgshapiro						A_TEMP,
87690792Sgshapiro						macid("{if_family}"), family);
87764562Sgshapiro					if (tTd(15, 7))
87890792Sgshapiro						sm_dprintf("getreq: got addr %s and family %s\n",
87990792Sgshapiro							addr, family);
88064562Sgshapiro				}
88164562Sgshapiro				else
88264562Sgshapiro				{
88390792Sgshapiro					macdefine(&BlankEnvelope.e_macro,
88490792Sgshapiro						A_PERM,
88590792Sgshapiro						macid("{if_addr}"), NULL);
88690792Sgshapiro					macdefine(&BlankEnvelope.e_macro,
88790792Sgshapiro						A_PERM,
88890792Sgshapiro						macid("{if_family}"), NULL);
88964562Sgshapiro				}
89064562Sgshapiro			}
89164562Sgshapiro			else
89264562Sgshapiro			{
89364562Sgshapiro				if (tTd(15, 7))
89490792Sgshapiro					sm_dprintf("getreq: getsockname failed\n");
89590792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
89690792Sgshapiro					macid("{if_name}"), NULL);
89790792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
89890792Sgshapiro					macid("{if_addr}"), NULL);
89990792Sgshapiro				macdefine(&BlankEnvelope.e_macro, A_PERM,
90090792Sgshapiro					macid("{if_family}"), NULL);
90164562Sgshapiro			}
90238032Speter			break;
90338032Speter		}
90438032Speter
90538032Speter		/* parent -- keep track of children */
90664562Sgshapiro		if (control)
90764562Sgshapiro		{
90890792Sgshapiro			(void) sm_snprintf(status, sizeof status,
90990792Sgshapiro					   "control socket server child");
910132943Sgshapiro			proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL);
91164562Sgshapiro		}
91264562Sgshapiro		else
91364562Sgshapiro		{
91490792Sgshapiro			(void) sm_snprintf(status, sizeof status,
91590792Sgshapiro					   "SMTP server child for %s",
91690792Sgshapiro					   anynet_ntoa(&RealHostAddr));
917132943Sgshapiro			proc_list_add(pid, status, PROC_DAEMON, 0, -1,
918132943Sgshapiro					&RealHostAddr);
91964562Sgshapiro		}
92090792Sgshapiro		(void) sm_releasesignal(SIGCHLD);
92138032Speter
92238032Speter		/* close the read end of the synchronization pipe */
92338032Speter		if (pipefd[0] != -1)
92464562Sgshapiro		{
92538032Speter			(void) close(pipefd[0]);
92664562Sgshapiro			pipefd[0] = -1;
92764562Sgshapiro		}
92838032Speter
92938032Speter		/* close the port so that others will hang (for a while) */
93038032Speter		(void) close(t);
93138032Speter
93238032Speter		/* release the child by closing the read end of the sync pipe */
93338032Speter		if (pipefd[1] != -1)
93464562Sgshapiro		{
93538032Speter			(void) close(pipefd[1]);
93664562Sgshapiro			pipefd[1] = -1;
93764562Sgshapiro		}
93838032Speter	}
93990792Sgshapiro	if (tTd(15, 2))
94090792Sgshapiro		sm_dprintf("getreq: returning\n");
94164562Sgshapiro
94290792Sgshapiro#if MILTER
94390792Sgshapiro	/* set the filters for this daemon */
94490792Sgshapiro	if (Daemons[curdaemon].d_inputfilterlist != NULL)
94590792Sgshapiro	{
94690792Sgshapiro		for (i = 0;
947110560Sgshapiro		     (i < MAXFILTERS &&
948110560Sgshapiro		      Daemons[curdaemon].d_inputfilters[i] != NULL);
94990792Sgshapiro		     i++)
95090792Sgshapiro		{
95190792Sgshapiro			InputFilters[i] = Daemons[curdaemon].d_inputfilters[i];
95290792Sgshapiro		}
95390792Sgshapiro		if (i < MAXFILTERS)
95490792Sgshapiro			InputFilters[i] = NULL;
95590792Sgshapiro	}
95690792Sgshapiro#endif /* MILTER */
95764562Sgshapiro	return &Daemons[curdaemon].d_flags;
95838032Speter}
95990792Sgshapiro
96090792Sgshapiro/*
96190792Sgshapiro**  GETREQUESTS_CHECKDISKSPACE -- check available diskspace.
96290792Sgshapiro**
96390792Sgshapiro**	Parameters:
96490792Sgshapiro**		e -- envelope.
96590792Sgshapiro**
96690792Sgshapiro**	Returns:
96790792Sgshapiro**		none.
96890792Sgshapiro**
96990792Sgshapiro**	Side Effects:
97090792Sgshapiro**		Modifies Daemon flags (D_ETRNONLY) if not enough disk space.
97190792Sgshapiro*/
97290792Sgshapiro
97390792Sgshapirostatic void
97490792Sgshapirogetrequests_checkdiskspace(e)
97590792Sgshapiro	ENVELOPE *e;
97690792Sgshapiro{
97790792Sgshapiro	bool logged = false;
97890792Sgshapiro	int idx;
97990792Sgshapiro	time_t now;
98090792Sgshapiro
98190792Sgshapiro	now = curtime();
98290792Sgshapiro	if (now < NextDiskSpaceCheck)
98390792Sgshapiro		return;
98490792Sgshapiro
98590792Sgshapiro	/* Check if there is available disk space in all queue groups. */
98690792Sgshapiro	if (!enoughdiskspace(0, NULL))
98790792Sgshapiro	{
98890792Sgshapiro		for (idx = 0; idx < NDaemons; ++idx)
98990792Sgshapiro		{
99090792Sgshapiro			if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
99190792Sgshapiro				continue;
99290792Sgshapiro
99390792Sgshapiro			/* log only if not logged before */
99490792Sgshapiro			if (!logged)
99590792Sgshapiro			{
99690792Sgshapiro				if (LogLevel > 8)
99790792Sgshapiro					sm_syslog(LOG_INFO, NOQID,
99890792Sgshapiro						  "rejecting new messages: min free: %ld",
99990792Sgshapiro						  MinBlocksFree);
100090792Sgshapiro				sm_setproctitle(true, e,
100190792Sgshapiro						"rejecting new messages: min free: %ld",
100290792Sgshapiro						MinBlocksFree);
100390792Sgshapiro				logged = true;
100490792Sgshapiro			}
100590792Sgshapiro			setbitn(D_ETRNONLY, Daemons[idx].d_flags);
100690792Sgshapiro		}
100790792Sgshapiro	}
100890792Sgshapiro	else
100990792Sgshapiro	{
101090792Sgshapiro		for (idx = 0; idx < NDaemons; ++idx)
101190792Sgshapiro		{
101290792Sgshapiro			if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
101390792Sgshapiro				continue;
101490792Sgshapiro
101590792Sgshapiro			/* log only if not logged before */
101690792Sgshapiro			if (!logged)
101790792Sgshapiro			{
101890792Sgshapiro				if (LogLevel > 8)
101990792Sgshapiro					sm_syslog(LOG_INFO, NOQID,
102090792Sgshapiro						  "accepting new messages (again)");
102190792Sgshapiro				logged = true;
102290792Sgshapiro			}
102390792Sgshapiro
102490792Sgshapiro			/* title will be set later */
102590792Sgshapiro			clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
102690792Sgshapiro		}
102790792Sgshapiro	}
102890792Sgshapiro
102990792Sgshapiro	/* only check disk space once a minute */
103090792Sgshapiro	NextDiskSpaceCheck = now + 60;
103190792Sgshapiro}
103290792Sgshapiro
103390792Sgshapiro/*
103464562Sgshapiro**  OPENDAEMONSOCKET -- open SMTP socket
103538032Speter**
103664562Sgshapiro**	Deals with setting all appropriate options.
103738032Speter**
103838032Speter**	Parameters:
103964562Sgshapiro**		d -- the structure for the daemon to open.
104038032Speter**		firsttime -- set if this is the initial open.
104138032Speter**
104238032Speter**	Returns:
104338032Speter**		Size in bytes of the daemon socket addr.
104438032Speter**
104538032Speter**	Side Effects:
104638032Speter**		Leaves DaemonSocket set to the open socket.
104738032Speter**		Exits if the socket cannot be created.
104838032Speter*/
104938032Speter
105090792Sgshapiro#define MAXOPENTRIES	10	/* maximum number of tries to open connection */
105138032Speter
105264562Sgshapirostatic int
105364562Sgshapiroopendaemonsocket(d, firsttime)
105490792Sgshapiro	DAEMON_T *d;
105538032Speter	bool firsttime;
105638032Speter{
105738032Speter	int on = 1;
105864562Sgshapiro	int fdflags;
105964562Sgshapiro	SOCKADDR_LEN_T socksize = 0;
106038032Speter	int ntries = 0;
106164562Sgshapiro	int save_errno;
106238032Speter
106338032Speter	if (tTd(15, 2))
106490792Sgshapiro		sm_dprintf("opendaemonsocket(%s)\n", d->d_name);
106538032Speter
106638032Speter	do
106738032Speter	{
106838032Speter		if (ntries > 0)
106964562Sgshapiro			(void) sleep(5);
107064562Sgshapiro		if (firsttime || d->d_socket < 0)
107138032Speter		{
107290792Sgshapiro#if _FFR_DAEMON_NETUNIX
107390792Sgshapiro# if NETUNIX
107490792Sgshapiro			if (d->d_addr.sa.sa_family == AF_UNIX)
107590792Sgshapiro			{
107690792Sgshapiro				int rval;
107790792Sgshapiro				long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT;
107890792Sgshapiro
107990792Sgshapiro				/* if not safe, don't use it */
108090792Sgshapiro				rval = safefile(d->d_addr.sunix.sun_path,
108190792Sgshapiro						RunAsUid, RunAsGid,
108290792Sgshapiro						RunAsUserName, sff,
108390792Sgshapiro						S_IRUSR|S_IWUSR, NULL);
108490792Sgshapiro				if (rval != 0)
108590792Sgshapiro				{
108690792Sgshapiro					save_errno = errno;
108790792Sgshapiro					syserr("opendaemonsocket: daemon %s: unsafe domain socket %s",
108890792Sgshapiro					       d->d_name,
108990792Sgshapiro					       d->d_addr.sunix.sun_path);
109090792Sgshapiro					goto fail;
109190792Sgshapiro				}
109290792Sgshapiro
109390792Sgshapiro				/* Don't try to overtake an existing socket */
109490792Sgshapiro				(void) unlink(d->d_addr.sunix.sun_path);
109590792Sgshapiro			}
109690792Sgshapiro# endif /* NETUNIX */
109790792Sgshapiro#endif /* _FFR_DOMAIN_NETUNIX */
109864562Sgshapiro			d->d_socket = socket(d->d_addr.sa.sa_family,
109964562Sgshapiro					     SOCK_STREAM, 0);
110064562Sgshapiro			if (d->d_socket < 0)
110138032Speter			{
110264562Sgshapiro				save_errno = errno;
110390792Sgshapiro				syserr("opendaemonsocket: daemon %s: can't create server SMTP socket",
110490792Sgshapiro				       d->d_name);
110590792Sgshapiro			  fail:
110690792Sgshapiro				if (bitnset(D_OPTIONAL, d->d_flags) &&
110790792Sgshapiro				    (!transienterror(save_errno) ||
110890792Sgshapiro				     ntries >= MAXOPENTRIES - 1))
110990792Sgshapiro				{
111090792Sgshapiro					syserr("opendaemonsocket: daemon %s: optional socket disabled",
111190792Sgshapiro					       d->d_name);
111290792Sgshapiro					setbitn(D_DISABLE, d->d_flags);
111390792Sgshapiro					d->d_socket = -1;
111490792Sgshapiro					return -1;
111590792Sgshapiro				}
111638032Speter			  severe:
111738032Speter				if (LogLevel > 0)
111838032Speter					sm_syslog(LOG_ALERT, NOQID,
111990792Sgshapiro						  "daemon %s: problem creating SMTP socket",
112090792Sgshapiro						  d->d_name);
112164562Sgshapiro				d->d_socket = -1;
112238032Speter				continue;
112338032Speter			}
112438032Speter
1125110560Sgshapiro			if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE)
1126110560Sgshapiro			{
1127110560Sgshapiro				save_errno = EINVAL;
1128110560Sgshapiro				syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large",
1129110560Sgshapiro				       d->d_name, d->d_socket);
1130110560Sgshapiro				goto fail;
1131110560Sgshapiro			}
1132110560Sgshapiro
113338032Speter			/* turn on network debugging? */
113438032Speter			if (tTd(15, 101))
113564562Sgshapiro				(void) setsockopt(d->d_socket, SOL_SOCKET,
113638032Speter						  SO_DEBUG, (char *)&on,
113738032Speter						  sizeof on);
113838032Speter
113964562Sgshapiro			(void) setsockopt(d->d_socket, SOL_SOCKET,
114038032Speter					  SO_REUSEADDR, (char *)&on, sizeof on);
114164562Sgshapiro			(void) setsockopt(d->d_socket, SOL_SOCKET,
114238032Speter					  SO_KEEPALIVE, (char *)&on, sizeof on);
114338032Speter
114490792Sgshapiro#ifdef SO_RCVBUF
114564562Sgshapiro			if (d->d_tcprcvbufsize > 0)
114638032Speter			{
114764562Sgshapiro				if (setsockopt(d->d_socket, SOL_SOCKET,
114838032Speter					       SO_RCVBUF,
114964562Sgshapiro					       (char *) &d->d_tcprcvbufsize,
115064562Sgshapiro					       sizeof(d->d_tcprcvbufsize)) < 0)
115164562Sgshapiro					syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
115238032Speter			}
115390792Sgshapiro#endif /* SO_RCVBUF */
115490792Sgshapiro#ifdef SO_SNDBUF
115564562Sgshapiro			if (d->d_tcpsndbufsize > 0)
115664562Sgshapiro			{
115764562Sgshapiro				if (setsockopt(d->d_socket, SOL_SOCKET,
115864562Sgshapiro					       SO_SNDBUF,
115964562Sgshapiro					       (char *) &d->d_tcpsndbufsize,
116064562Sgshapiro					       sizeof(d->d_tcpsndbufsize)) < 0)
116164562Sgshapiro					syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
116264562Sgshapiro			}
116390792Sgshapiro#endif /* SO_SNDBUF */
116438032Speter
116564562Sgshapiro			if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
116664562Sgshapiro			    fcntl(d->d_socket, F_SETFD,
116764562Sgshapiro				  fdflags | FD_CLOEXEC) == -1)
116838032Speter			{
116964562Sgshapiro				save_errno = errno;
117064562Sgshapiro				syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
117164562Sgshapiro				       d->d_name,
117264562Sgshapiro				       fdflags == -1 ? "get" : "set",
117390792Sgshapiro				       sm_errstring(save_errno));
117464562Sgshapiro				(void) close(d->d_socket);
117564562Sgshapiro				goto severe;
117664562Sgshapiro			}
117764562Sgshapiro
117864562Sgshapiro			switch (d->d_addr.sa.sa_family)
117964562Sgshapiro			{
118090792Sgshapiro#if _FFR_DAEMON_NETUNIX
118190792Sgshapiro# ifdef NETUNIX
118290792Sgshapiro			  case AF_UNIX:
118390792Sgshapiro				socksize = sizeof d->d_addr.sunix;
118490792Sgshapiro				break;
118590792Sgshapiro# endif /* NETUNIX */
118690792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */
118790792Sgshapiro#if NETINET
118838032Speter			  case AF_INET:
118964562Sgshapiro				socksize = sizeof d->d_addr.sin;
119038032Speter				break;
119190792Sgshapiro#endif /* NETINET */
119238032Speter
119390792Sgshapiro#if NETINET6
119464562Sgshapiro			  case AF_INET6:
119564562Sgshapiro				socksize = sizeof d->d_addr.sin6;
119664562Sgshapiro				break;
119790792Sgshapiro#endif /* NETINET6 */
119864562Sgshapiro
119990792Sgshapiro#if NETISO
120038032Speter			  case AF_ISO:
120164562Sgshapiro				socksize = sizeof d->d_addr.siso;
120238032Speter				break;
120390792Sgshapiro#endif /* NETISO */
120438032Speter
120538032Speter			  default:
120664562Sgshapiro				socksize = sizeof d->d_addr;
120738032Speter				break;
120838032Speter			}
120938032Speter
121064562Sgshapiro			if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
121138032Speter			{
121238032Speter				/* probably another daemon already */
121364562Sgshapiro				save_errno = errno;
121464562Sgshapiro				syserr("opendaemonsocket: daemon %s: cannot bind",
121564562Sgshapiro				       d->d_name);
121664562Sgshapiro				(void) close(d->d_socket);
121790792Sgshapiro				goto fail;
121838032Speter			}
121938032Speter		}
122064562Sgshapiro		if (!firsttime &&
122164562Sgshapiro		    listen(d->d_socket, d->d_listenqueue) < 0)
122238032Speter		{
122364562Sgshapiro			save_errno = errno;
122464562Sgshapiro			syserr("opendaemonsocket: daemon %s: cannot listen",
122564562Sgshapiro			       d->d_name);
122664562Sgshapiro			(void) close(d->d_socket);
122738032Speter			goto severe;
122838032Speter		}
122938032Speter		return socksize;
123064562Sgshapiro	} while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
123164562Sgshapiro	syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
123264562Sgshapiro	       d->d_name);
123364562Sgshapiro	/* NOTREACHED */
123438032Speter	return -1;  /* avoid compiler warning on IRIX */
123538032Speter}
123690792Sgshapiro/*
123764562Sgshapiro**  SETUPDAEMON -- setup socket for daemon
123864562Sgshapiro**
123964562Sgshapiro**	Parameters:
124064562Sgshapiro**		daemonaddr -- socket for daemon
124164562Sgshapiro**
124264562Sgshapiro**	Returns:
124364562Sgshapiro**		port number on which daemon should run
124464562Sgshapiro**
124564562Sgshapiro*/
124690792Sgshapiro
124790792Sgshapirostatic unsigned short
124864562Sgshapirosetupdaemon(daemonaddr)
124964562Sgshapiro	SOCKADDR *daemonaddr;
125064562Sgshapiro{
125190792Sgshapiro	unsigned short port;
125264562Sgshapiro
125364562Sgshapiro	/*
125464562Sgshapiro	**  Set up the address for the mailer.
125564562Sgshapiro	*/
125664562Sgshapiro
125764562Sgshapiro	if (daemonaddr->sa.sa_family == AF_UNSPEC)
125864562Sgshapiro	{
125964562Sgshapiro		memset(daemonaddr, '\0', sizeof *daemonaddr);
126090792Sgshapiro#if NETINET
126164562Sgshapiro		daemonaddr->sa.sa_family = AF_INET;
126290792Sgshapiro#endif /* NETINET */
126364562Sgshapiro	}
126464562Sgshapiro
126564562Sgshapiro	switch (daemonaddr->sa.sa_family)
126664562Sgshapiro	{
126790792Sgshapiro#if NETINET
126864562Sgshapiro	  case AF_INET:
126964562Sgshapiro		if (daemonaddr->sin.sin_addr.s_addr == 0)
127064562Sgshapiro			daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
127164562Sgshapiro		port = daemonaddr->sin.sin_port;
127264562Sgshapiro		break;
127390792Sgshapiro#endif /* NETINET */
127464562Sgshapiro
127590792Sgshapiro#if NETINET6
127664562Sgshapiro	  case AF_INET6:
127764562Sgshapiro		if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
127864562Sgshapiro			daemonaddr->sin6.sin6_addr = in6addr_any;
127964562Sgshapiro		port = daemonaddr->sin6.sin6_port;
128064562Sgshapiro		break;
128190792Sgshapiro#endif /* NETINET6 */
128264562Sgshapiro
128364562Sgshapiro	  default:
128464562Sgshapiro		/* unknown protocol */
128564562Sgshapiro		port = 0;
128664562Sgshapiro		break;
128764562Sgshapiro	}
128864562Sgshapiro	if (port == 0)
128964562Sgshapiro	{
129090792Sgshapiro#ifdef NO_GETSERVBYNAME
129164562Sgshapiro		port = htons(25);
129290792Sgshapiro#else /* NO_GETSERVBYNAME */
129364562Sgshapiro		{
129464562Sgshapiro			register struct servent *sp;
129564562Sgshapiro
129664562Sgshapiro			sp = getservbyname("smtp", "tcp");
129764562Sgshapiro			if (sp == NULL)
129864562Sgshapiro			{
129964562Sgshapiro				syserr("554 5.3.5 service \"smtp\" unknown");
130064562Sgshapiro				port = htons(25);
130164562Sgshapiro			}
130264562Sgshapiro			else
130364562Sgshapiro				port = sp->s_port;
130464562Sgshapiro		}
130590792Sgshapiro#endif /* NO_GETSERVBYNAME */
130664562Sgshapiro	}
130764562Sgshapiro
130864562Sgshapiro	switch (daemonaddr->sa.sa_family)
130964562Sgshapiro	{
131090792Sgshapiro#if NETINET
131164562Sgshapiro	  case AF_INET:
131264562Sgshapiro		daemonaddr->sin.sin_port = port;
131364562Sgshapiro		break;
131490792Sgshapiro#endif /* NETINET */
131564562Sgshapiro
131690792Sgshapiro#if NETINET6
131764562Sgshapiro	  case AF_INET6:
131864562Sgshapiro		daemonaddr->sin6.sin6_port = port;
131964562Sgshapiro		break;
132090792Sgshapiro#endif /* NETINET6 */
132164562Sgshapiro
132264562Sgshapiro	  default:
132364562Sgshapiro		/* unknown protocol */
132464562Sgshapiro		break;
132564562Sgshapiro	}
132690792Sgshapiro	return port;
132764562Sgshapiro}
132890792Sgshapiro/*
132938032Speter**  CLRDAEMON -- reset the daemon connection
133038032Speter**
133138032Speter**	Parameters:
133238032Speter**		none.
133338032Speter**
133438032Speter**	Returns:
133538032Speter**		none.
133638032Speter**
133738032Speter**	Side Effects:
133838032Speter**		releases any resources used by the passive daemon.
133938032Speter*/
134038032Speter
134138032Spetervoid
134238032Speterclrdaemon()
134338032Speter{
134464562Sgshapiro	int i;
134564562Sgshapiro
134690792Sgshapiro	for (i = 0; i < NDaemons; i++)
134764562Sgshapiro	{
134864562Sgshapiro		if (Daemons[i].d_socket >= 0)
134964562Sgshapiro			(void) close(Daemons[i].d_socket);
135064562Sgshapiro		Daemons[i].d_socket = -1;
135164562Sgshapiro	}
135238032Speter}
135390792Sgshapiro
135490792Sgshapiro/*
135590792Sgshapiro**  GETMODIFIERS -- get modifier flags
135690792Sgshapiro**
135790792Sgshapiro**	Parameters:
135890792Sgshapiro**		v -- the modifiers (input text line).
135990792Sgshapiro**		modifiers -- pointer to flag field to represent modifiers.
136090792Sgshapiro**
136190792Sgshapiro**	Returns:
136290792Sgshapiro**		(xallocat()ed) string representation of modifiers.
136390792Sgshapiro**
136490792Sgshapiro**	Side Effects:
136590792Sgshapiro**		fills in modifiers.
136690792Sgshapiro*/
136790792Sgshapiro
136890792Sgshapirochar *
136990792Sgshapirogetmodifiers(v, modifiers)
137090792Sgshapiro	char *v;
137190792Sgshapiro	BITMAP256 modifiers;
137290792Sgshapiro{
137390792Sgshapiro	int l;
137490792Sgshapiro	char *h, *f, *flags;
137590792Sgshapiro
137690792Sgshapiro	/* maximum length of flags: upper case Option -> "OO " */
137790792Sgshapiro	l = 3 * strlen(v) + 3;
137890792Sgshapiro
137990792Sgshapiro	/* is someone joking? */
138090792Sgshapiro	if (l < 0 || l > 256)
138190792Sgshapiro	{
138290792Sgshapiro		if (LogLevel > 2)
138390792Sgshapiro			sm_syslog(LOG_ERR, NOQID,
138490792Sgshapiro				  "getmodifiers too long, ignored");
138590792Sgshapiro		return NULL;
138690792Sgshapiro	}
138790792Sgshapiro	flags = xalloc(l);
138890792Sgshapiro	f = flags;
138990792Sgshapiro	clrbitmap(modifiers);
139090792Sgshapiro	for (h = v; *h != '\0'; h++)
139190792Sgshapiro	{
139290792Sgshapiro		if (isascii(*h) && !isspace(*h) && isprint(*h))
139390792Sgshapiro		{
139490792Sgshapiro			setbitn(*h, modifiers);
139590792Sgshapiro			if (flags != f)
139690792Sgshapiro				*flags++ = ' ';
139790792Sgshapiro			*flags++ = *h;
139890792Sgshapiro			if (isupper(*h))
139990792Sgshapiro				*flags++ = *h;
140090792Sgshapiro		}
140190792Sgshapiro	}
140290792Sgshapiro	*flags++ = '\0';
140390792Sgshapiro	return f;
140490792Sgshapiro}
140590792Sgshapiro
140690792Sgshapiro/*
140790792Sgshapiro**  CHKDAEMONMODIFIERS -- check whether all daemons have set a flag.
140890792Sgshapiro**
140990792Sgshapiro**	Parameters:
141090792Sgshapiro**		flag -- the flag to test.
141190792Sgshapiro**
141290792Sgshapiro**	Returns:
141390792Sgshapiro**		true iff all daemons have set flag.
141490792Sgshapiro*/
141590792Sgshapiro
141690792Sgshapirobool
141790792Sgshapirochkdaemonmodifiers(flag)
141890792Sgshapiro	int flag;
141990792Sgshapiro{
142090792Sgshapiro	int i;
142190792Sgshapiro
142290792Sgshapiro	for (i = 0; i < NDaemons; i++)
142390792Sgshapiro		if (!bitnset((char) flag, Daemons[i].d_flags))
142490792Sgshapiro			return false;
142590792Sgshapiro	return true;
142690792Sgshapiro}
142790792Sgshapiro
142890792Sgshapiro/*
142964562Sgshapiro**  SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
143038032Speter**
143138032Speter**	Parameters:
143238032Speter**		p -- the options line.
143364562Sgshapiro**		d -- the daemon structure to fill in.
143438032Speter**
143538032Speter**	Returns:
143638032Speter**		none.
143738032Speter*/
143838032Speter
143964562Sgshapirostatic void
144064562Sgshapirosetsockaddroptions(p, d)
1441141858Sgshapiro	char *p;
144290792Sgshapiro	DAEMON_T *d;
144338032Speter{
144490792Sgshapiro#if NETISO
144571345Sgshapiro	short portno;
144690792Sgshapiro#endif /* NETISO */
144771345Sgshapiro	char *port = NULL;
144871345Sgshapiro	char *addr = NULL;
144938032Speter
145090792Sgshapiro#if NETINET
145164562Sgshapiro	if (d->d_addr.sa.sa_family == AF_UNSPEC)
145264562Sgshapiro		d->d_addr.sa.sa_family = AF_INET;
145390792Sgshapiro#endif /* NETINET */
1454157001Sgshapiro#if _FFR_SS_PER_DAEMON
1455157001Sgshapiro	d->d_supersafe = SAFE_NOTSET;
1456157001Sgshapiro#endif /* _FFR_SS_PER_DAEMON */
1457157001Sgshapiro#if _FFR_DM_PER_DAEMON
1458157001Sgshapiro	d->d_dm = DM_NOTSET;
1459157001Sgshapiro#endif /* _FFR_DM_PER_DAEMON */
146064562Sgshapiro
146138032Speter	while (p != NULL)
146238032Speter	{
146338032Speter		register char *f;
146438032Speter		register char *v;
146538032Speter
146638032Speter		while (isascii(*p) && isspace(*p))
146738032Speter			p++;
146838032Speter		if (*p == '\0')
146938032Speter			break;
147038032Speter		f = p;
147138032Speter		p = strchr(p, ',');
147238032Speter		if (p != NULL)
147338032Speter			*p++ = '\0';
147438032Speter		v = strchr(f, '=');
147538032Speter		if (v == NULL)
147638032Speter			continue;
147738032Speter		while (isascii(*++v) && isspace(*v))
147838032Speter			continue;
147938032Speter		if (isascii(*f) && islower(*f))
148038032Speter			*f = toupper(*f);
148138032Speter
148238032Speter		switch (*f)
148338032Speter		{
1484147078Sgshapiro		  case 'A':		/* address */
1485147078Sgshapiro			addr = v;
1486147078Sgshapiro			break;
1487147078Sgshapiro
1488147078Sgshapiro#if _FFR_DM_PER_DAEMON
1489147078Sgshapiro		  case 'D':		/* DeliveryMode */
1490147078Sgshapiro			switch (*v)
1491147078Sgshapiro			{
1492147078Sgshapiro			  case SM_QUEUE:
1493147078Sgshapiro			  case SM_DEFER:
1494147078Sgshapiro			  case SM_DELIVER:
1495157001Sgshapiro			  case SM_FORK:
1496147078Sgshapiro				d->d_dm = *v;
1497147078Sgshapiro				break;
1498147078Sgshapiro			  default:
1499147078Sgshapiro				syserr("554 5.3.5 Unknown delivery mode %c",
1500147078Sgshapiro					*v);
1501147078Sgshapiro				break;
1502147078Sgshapiro			}
1503147078Sgshapiro			break;
1504147078Sgshapiro#endif /* _FFR_DM_PER_DAEMON */
1505147078Sgshapiro
150638032Speter		  case 'F':		/* address family */
150738032Speter			if (isascii(*v) && isdigit(*v))
150864562Sgshapiro				d->d_addr.sa.sa_family = atoi(v);
150990792Sgshapiro#if _FFR_DAEMON_NETUNIX
151090792Sgshapiro# ifdef NETUNIX
151190792Sgshapiro			else if (sm_strcasecmp(v, "unix") == 0 ||
151290792Sgshapiro				 sm_strcasecmp(v, "local") == 0)
151390792Sgshapiro				d->d_addr.sa.sa_family = AF_UNIX;
151490792Sgshapiro# endif /* NETUNIX */
151590792Sgshapiro#endif /* _FFR_DAEMON_NETUNIX */
151690792Sgshapiro#if NETINET
151790792Sgshapiro			else if (sm_strcasecmp(v, "inet") == 0)
151864562Sgshapiro				d->d_addr.sa.sa_family = AF_INET;
151990792Sgshapiro#endif /* NETINET */
152090792Sgshapiro#if NETINET6
152190792Sgshapiro			else if (sm_strcasecmp(v, "inet6") == 0)
152264562Sgshapiro				d->d_addr.sa.sa_family = AF_INET6;
152390792Sgshapiro#endif /* NETINET6 */
152490792Sgshapiro#if NETISO
152590792Sgshapiro			else if (sm_strcasecmp(v, "iso") == 0)
152664562Sgshapiro				d->d_addr.sa.sa_family = AF_ISO;
152790792Sgshapiro#endif /* NETISO */
152890792Sgshapiro#if NETNS
152990792Sgshapiro			else if (sm_strcasecmp(v, "ns") == 0)
153064562Sgshapiro				d->d_addr.sa.sa_family = AF_NS;
153190792Sgshapiro#endif /* NETNS */
153290792Sgshapiro#if NETX25
153390792Sgshapiro			else if (sm_strcasecmp(v, "x.25") == 0)
153464562Sgshapiro				d->d_addr.sa.sa_family = AF_CCITT;
153590792Sgshapiro#endif /* NETX25 */
153638032Speter			else
153764562Sgshapiro				syserr("554 5.3.5 Unknown address family %s in Family=option",
153864562Sgshapiro				       v);
153938032Speter			break;
154038032Speter
154190792Sgshapiro#if MILTER
154290792Sgshapiro		  case 'I':
154390792Sgshapiro			d->d_inputfilterlist = v;
154490792Sgshapiro			break;
154590792Sgshapiro#endif /* MILTER */
154690792Sgshapiro
154738032Speter		  case 'L':		/* listen queue size */
154864562Sgshapiro			d->d_listenqueue = atoi(v);
154938032Speter			break;
155038032Speter
155164562Sgshapiro		  case 'M':		/* modifiers (flags) */
155290792Sgshapiro			d->d_mflags = getmodifiers(v, d->d_flags);
155364562Sgshapiro			break;
155464562Sgshapiro
1555147078Sgshapiro		  case 'N':		/* name */
1556147078Sgshapiro			d->d_name = v;
155738032Speter			break;
155838032Speter
1559147078Sgshapiro		  case 'P':		/* port */
1560147078Sgshapiro			port = v;
1561147078Sgshapiro			break;
1562147078Sgshapiro
156338032Speter		  case 'R':		/* receive buffer size */
156464562Sgshapiro			d->d_tcprcvbufsize = atoi(v);
156538032Speter			break;
156638032Speter
1567147078Sgshapiro		  case 'S':		/* send buffer size */
1568147078Sgshapiro			d->d_tcpsndbufsize = atoi(v);
156964562Sgshapiro			break;
157064562Sgshapiro
1571147078Sgshapiro#if _FFR_SS_PER_DAEMON
1572147078Sgshapiro		  case 'T':		/* SuperSafe */
1573147078Sgshapiro			if (tolower(*v) == 'i')
1574147078Sgshapiro				d->d_supersafe = SAFE_INTERACTIVE;
1575147078Sgshapiro			else if (tolower(*v) == 'p')
1576147078Sgshapiro# if MILTER
1577147078Sgshapiro				d->d_supersafe = SAFE_REALLY_POSTMILTER;
1578147078Sgshapiro# else /* MILTER */
1579147078Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1580147078Sgshapiro					"Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n");
1581147078Sgshapiro# endif /* MILTER */
1582147078Sgshapiro			else
1583147078Sgshapiro				d->d_supersafe = atobool(v) ? SAFE_REALLY
1584147078Sgshapiro							: SAFE_NO;
1585147078Sgshapiro			break;
1586147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */
1587147078Sgshapiro
158838032Speter		  default:
158964562Sgshapiro			syserr("554 5.3.5 PortOptions parameter \"%s\" unknown",
159064562Sgshapiro			       f);
159138032Speter		}
159238032Speter	}
159371345Sgshapiro
159471345Sgshapiro	/* Check addr and port after finding family */
159571345Sgshapiro	if (addr != NULL)
159671345Sgshapiro	{
159771345Sgshapiro		switch (d->d_addr.sa.sa_family)
159871345Sgshapiro		{
159990792Sgshapiro#if _FFR_DAEMON_NETUNIX
160090792Sgshapiro# if NETUNIX
160190792Sgshapiro		  case AF_UNIX:
160290792Sgshapiro			if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path))
160390792Sgshapiro			{
160490792Sgshapiro				errno = ENAMETOOLONG;
160590792Sgshapiro				syserr("setsockaddroptions: domain socket name too long: %s > %d",
160690792Sgshapiro				       addr, sizeof(d->d_addr.sunix.sun_path));
160790792Sgshapiro				break;
160890792Sgshapiro			}
160990792Sgshapiro
161090792Sgshapiro			/* file safety check done in opendaemonsocket() */
161190792Sgshapiro			(void) memset(&d->d_addr.sunix.sun_path, '\0',
161290792Sgshapiro				      sizeof(d->d_addr.sunix.sun_path));
161390792Sgshapiro			(void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path,
161490792Sgshapiro					  addr,
161590792Sgshapiro					  sizeof(d->d_addr.sunix.sun_path));
161690792Sgshapiro			break;
161790792Sgshapiro# endif /* NETUNIX */
161890792Sgshapiro#endif	/* _FFR_DAEMON_NETUNIX */
161990792Sgshapiro#if NETINET
162071345Sgshapiro		  case AF_INET:
162171345Sgshapiro			if (!isascii(*addr) || !isdigit(*addr) ||
162290792Sgshapiro			    ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr))
162390792Sgshapiro			     == INADDR_NONE))
162471345Sgshapiro			{
162571345Sgshapiro				register struct hostent *hp;
162671345Sgshapiro
162771345Sgshapiro				hp = sm_gethostbyname(addr, AF_INET);
162871345Sgshapiro				if (hp == NULL)
162971345Sgshapiro					syserr("554 5.3.0 host \"%s\" unknown",
163071345Sgshapiro					       addr);
163171345Sgshapiro				else
163271345Sgshapiro				{
163371345Sgshapiro					while (*(hp->h_addr_list) != NULL &&
163471345Sgshapiro					       hp->h_addrtype != AF_INET)
163571345Sgshapiro						hp->h_addr_list++;
163671345Sgshapiro					if (*(hp->h_addr_list) == NULL)
163771345Sgshapiro						syserr("554 5.3.0 host \"%s\" unknown",
163871345Sgshapiro						       addr);
163971345Sgshapiro					else
164071345Sgshapiro						memmove(&d->d_addr.sin.sin_addr,
164171345Sgshapiro							*(hp->h_addr_list),
164271345Sgshapiro							INADDRSZ);
164390792Sgshapiro# if NETINET6
164471345Sgshapiro					freehostent(hp);
164571345Sgshapiro					hp = NULL;
164690792Sgshapiro# endif /* NETINET6 */
164771345Sgshapiro				}
164871345Sgshapiro			}
164971345Sgshapiro			break;
165090792Sgshapiro#endif /* NETINET */
165171345Sgshapiro
165290792Sgshapiro#if NETINET6
165371345Sgshapiro		  case AF_INET6:
165490792Sgshapiro			if (anynet_pton(AF_INET6, addr,
165590792Sgshapiro					&d->d_addr.sin6.sin6_addr) != 1)
165671345Sgshapiro			{
165771345Sgshapiro				register struct hostent *hp;
165871345Sgshapiro
165971345Sgshapiro				hp = sm_gethostbyname(addr, AF_INET6);
166071345Sgshapiro				if (hp == NULL)
166171345Sgshapiro					syserr("554 5.3.0 host \"%s\" unknown",
166271345Sgshapiro					       addr);
166371345Sgshapiro				else
166471345Sgshapiro				{
166571345Sgshapiro					while (*(hp->h_addr_list) != NULL &&
166671345Sgshapiro					       hp->h_addrtype != AF_INET6)
166771345Sgshapiro						hp->h_addr_list++;
166871345Sgshapiro					if (*(hp->h_addr_list) == NULL)
166971345Sgshapiro						syserr("554 5.3.0 host \"%s\" unknown",
167071345Sgshapiro						       addr);
167171345Sgshapiro					else
167271345Sgshapiro						memmove(&d->d_addr.sin6.sin6_addr,
167371345Sgshapiro							*(hp->h_addr_list),
167471345Sgshapiro							IN6ADDRSZ);
167571345Sgshapiro					freehostent(hp);
167671345Sgshapiro					hp = NULL;
167771345Sgshapiro				}
167871345Sgshapiro			}
167971345Sgshapiro			break;
168090792Sgshapiro#endif /* NETINET6 */
168171345Sgshapiro
168271345Sgshapiro		  default:
168371345Sgshapiro			syserr("554 5.3.5 address= option unsupported for family %d",
168471345Sgshapiro			       d->d_addr.sa.sa_family);
168571345Sgshapiro			break;
168671345Sgshapiro		}
168771345Sgshapiro	}
168871345Sgshapiro
168971345Sgshapiro	if (port != NULL)
169071345Sgshapiro	{
169171345Sgshapiro		switch (d->d_addr.sa.sa_family)
169271345Sgshapiro		{
169390792Sgshapiro#if NETINET
169471345Sgshapiro		  case AF_INET:
169571345Sgshapiro			if (isascii(*port) && isdigit(*port))
169690792Sgshapiro				d->d_addr.sin.sin_port = htons((unsigned short)
169790792Sgshapiro						     atoi((const char *) port));
169871345Sgshapiro			else
169971345Sgshapiro			{
170090792Sgshapiro# ifdef NO_GETSERVBYNAME
170171345Sgshapiro				syserr("554 5.3.5 invalid port number: %s",
170271345Sgshapiro				       port);
170390792Sgshapiro# else /* NO_GETSERVBYNAME */
170471345Sgshapiro				register struct servent *sp;
170571345Sgshapiro
170671345Sgshapiro				sp = getservbyname(port, "tcp");
170771345Sgshapiro				if (sp == NULL)
170871345Sgshapiro					syserr("554 5.3.5 service \"%s\" unknown",
170971345Sgshapiro					       port);
171071345Sgshapiro				else
171171345Sgshapiro					d->d_addr.sin.sin_port = sp->s_port;
171290792Sgshapiro# endif /* NO_GETSERVBYNAME */
171371345Sgshapiro			}
171471345Sgshapiro			break;
171590792Sgshapiro#endif /* NETINET */
171671345Sgshapiro
171790792Sgshapiro#if NETINET6
171871345Sgshapiro		  case AF_INET6:
171971345Sgshapiro			if (isascii(*port) && isdigit(*port))
172090792Sgshapiro				d->d_addr.sin6.sin6_port = htons((unsigned short)
172190792Sgshapiro								  atoi(port));
172271345Sgshapiro			else
172371345Sgshapiro			{
172490792Sgshapiro# ifdef NO_GETSERVBYNAME
172571345Sgshapiro				syserr("554 5.3.5 invalid port number: %s",
172671345Sgshapiro				       port);
172790792Sgshapiro# else /* NO_GETSERVBYNAME */
172871345Sgshapiro				register struct servent *sp;
172971345Sgshapiro
173071345Sgshapiro				sp = getservbyname(port, "tcp");
173171345Sgshapiro				if (sp == NULL)
173271345Sgshapiro					syserr("554 5.3.5 service \"%s\" unknown",
173371345Sgshapiro					       port);
173471345Sgshapiro				else
173571345Sgshapiro					d->d_addr.sin6.sin6_port = sp->s_port;
173690792Sgshapiro# endif /* NO_GETSERVBYNAME */
173771345Sgshapiro			}
173871345Sgshapiro			break;
173990792Sgshapiro#endif /* NETINET6 */
174071345Sgshapiro
174190792Sgshapiro#if NETISO
174271345Sgshapiro		  case AF_ISO:
174371345Sgshapiro			/* assume two byte transport selector */
174471345Sgshapiro			if (isascii(*port) && isdigit(*port))
174590792Sgshapiro				portno = htons((unsigned short) atoi(port));
174671345Sgshapiro			else
174771345Sgshapiro			{
174890792Sgshapiro# ifdef NO_GETSERVBYNAME
174971345Sgshapiro				syserr("554 5.3.5 invalid port number: %s",
175071345Sgshapiro				       port);
175190792Sgshapiro# else /* NO_GETSERVBYNAME */
175271345Sgshapiro				register struct servent *sp;
175371345Sgshapiro
175471345Sgshapiro				sp = getservbyname(port, "tcp");
175571345Sgshapiro				if (sp == NULL)
175671345Sgshapiro					syserr("554 5.3.5 service \"%s\" unknown",
175771345Sgshapiro					       port);
175871345Sgshapiro				else
175971345Sgshapiro					portno = sp->s_port;
176090792Sgshapiro# endif /* NO_GETSERVBYNAME */
176171345Sgshapiro			}
176271345Sgshapiro			memmove(TSEL(&d->d_addr.siso),
176371345Sgshapiro				(char *) &portno, 2);
176471345Sgshapiro			break;
176590792Sgshapiro#endif /* NETISO */
176671345Sgshapiro
176771345Sgshapiro		  default:
176871345Sgshapiro			syserr("554 5.3.5 Port= option unsupported for family %d",
176971345Sgshapiro			       d->d_addr.sa.sa_family);
177071345Sgshapiro			break;
177171345Sgshapiro		}
177271345Sgshapiro	}
177338032Speter}
177490792Sgshapiro/*
177564562Sgshapiro**  SETDAEMONOPTIONS -- set options for running the MTA daemon
177638032Speter**
177738032Speter**	Parameters:
177864562Sgshapiro**		p -- the options line.
177964562Sgshapiro**
178064562Sgshapiro**	Returns:
178190792Sgshapiro**		true if successful, false otherwise.
178290792Sgshapiro**
178390792Sgshapiro**	Side Effects:
178490792Sgshapiro**		increments number of daemons.
178564562Sgshapiro*/
178664562Sgshapiro
178790792Sgshapiro#define DEF_LISTENQUEUE	10
178890792Sgshapiro
178998841Sgshapirostruct dflags
179098841Sgshapiro{
179198841Sgshapiro	char	*d_name;
179298841Sgshapiro	int	d_flag;
179398841Sgshapiro};
179498841Sgshapiro
179598841Sgshapirostatic struct dflags	DaemonFlags[] =
179698841Sgshapiro{
179798841Sgshapiro	{ "AUTHREQ",		D_AUTHREQ	},
179898841Sgshapiro	{ "BINDIF",		D_BINDIF	},
179998841Sgshapiro	{ "CANONREQ",		D_CANONREQ	},
180098841Sgshapiro	{ "IFNHELO",		D_IFNHELO	},
180198841Sgshapiro	{ "FQMAIL",		D_FQMAIL	},
180298841Sgshapiro	{ "FQRCPT",		D_FQRCPT	},
180398841Sgshapiro	{ "SMTPS",		D_SMTPS		},
180498841Sgshapiro	{ "UNQUALOK",		D_UNQUALOK	},
180598841Sgshapiro	{ "NOAUTH",		D_NOAUTH	},
180698841Sgshapiro	{ "NOCANON",		D_NOCANON	},
180798841Sgshapiro	{ "NOETRN",		D_NOETRN	},
180898841Sgshapiro	{ "NOTLS",		D_NOTLS		},
180998841Sgshapiro	{ "ETRNONLY",		D_ETRNONLY	},
181098841Sgshapiro	{ "OPTIONAL",		D_OPTIONAL	},
181198841Sgshapiro	{ "DISABLE",		D_DISABLE	},
181298841Sgshapiro	{ "ISSET",		D_ISSET		},
181398841Sgshapiro	{ NULL,			0		}
181498841Sgshapiro};
181598841Sgshapiro
181698841Sgshapirostatic void
181798841Sgshapiroprintdaemonflags(d)
181898841Sgshapiro	DAEMON_T *d;
181998841Sgshapiro{
182098841Sgshapiro	register struct dflags *df;
182198841Sgshapiro	bool first = true;
182298841Sgshapiro
182398841Sgshapiro	for (df = DaemonFlags; df->d_name != NULL; df++)
182498841Sgshapiro	{
182598841Sgshapiro		if (!bitnset(df->d_flag, d->d_flags))
182698841Sgshapiro			continue;
182798841Sgshapiro		if (first)
1828132943Sgshapiro			sm_dprintf("<%s", df->d_name);
182998841Sgshapiro		else
1830132943Sgshapiro			sm_dprintf(",%s", df->d_name);
183198841Sgshapiro		first = false;
183298841Sgshapiro	}
183398841Sgshapiro	if (!first)
1834132943Sgshapiro		sm_dprintf(">");
183598841Sgshapiro}
183698841Sgshapiro
183764562Sgshapirobool
183864562Sgshapirosetdaemonoptions(p)
183964562Sgshapiro	register char *p;
184064562Sgshapiro{
184190792Sgshapiro	if (NDaemons >= MAXDAEMONS)
184290792Sgshapiro		return false;
184390792Sgshapiro	Daemons[NDaemons].d_socket = -1;
184490792Sgshapiro	Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
184590792Sgshapiro	clrbitmap(Daemons[NDaemons].d_flags);
184690792Sgshapiro	setsockaddroptions(p, &Daemons[NDaemons]);
184764562Sgshapiro
184890792Sgshapiro#if MILTER
184990792Sgshapiro	if (Daemons[NDaemons].d_inputfilterlist != NULL)
185090792Sgshapiro		Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist);
185190792Sgshapiro#endif /* MILTER */
185290792Sgshapiro
185390792Sgshapiro	if (Daemons[NDaemons].d_name != NULL)
185490792Sgshapiro		Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name);
185564562Sgshapiro	else
185664562Sgshapiro	{
185764562Sgshapiro		char num[30];
185864562Sgshapiro
185990792Sgshapiro		(void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons);
186090792Sgshapiro		Daemons[NDaemons].d_name = newstr(num);
186164562Sgshapiro	}
186264562Sgshapiro
186364562Sgshapiro	if (tTd(37, 1))
186464562Sgshapiro	{
186590792Sgshapiro		sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name);
186698841Sgshapiro		printdaemonflags(&Daemons[NDaemons]);
186790792Sgshapiro		sm_dprintf("\n");
186864562Sgshapiro	}
186990792Sgshapiro	++NDaemons;
187090792Sgshapiro	return true;
187164562Sgshapiro}
187290792Sgshapiro/*
187364562Sgshapiro**  INITDAEMON -- initialize daemon if not yet done.
187464562Sgshapiro**
187564562Sgshapiro**	Parameters:
187664562Sgshapiro**		none
187764562Sgshapiro**
187864562Sgshapiro**	Returns:
187964562Sgshapiro**		none
188064562Sgshapiro**
188164562Sgshapiro**	Side Effects:
188264562Sgshapiro**		initializes structure for one daemon.
188364562Sgshapiro*/
188490792Sgshapiro
188564562Sgshapirovoid
188664562Sgshapiroinitdaemon()
188764562Sgshapiro{
188890792Sgshapiro	if (NDaemons == 0)
188964562Sgshapiro	{
189090792Sgshapiro		Daemons[NDaemons].d_socket = -1;
189190792Sgshapiro		Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
189290792Sgshapiro		Daemons[NDaemons].d_name = "Daemon0";
189390792Sgshapiro		NDaemons = 1;
189464562Sgshapiro	}
189564562Sgshapiro}
189690792Sgshapiro/*
189764562Sgshapiro**  SETCLIENTOPTIONS -- set options for running the client
189864562Sgshapiro**
189964562Sgshapiro**	Parameters:
190064562Sgshapiro**		p -- the options line.
190164562Sgshapiro**
190264562Sgshapiro**	Returns:
190364562Sgshapiro**		none.
190464562Sgshapiro*/
190564562Sgshapiro
190690792Sgshapirostatic DAEMON_T	ClientSettings[AF_MAX + 1];
190764562Sgshapiro
190864562Sgshapirovoid
190964562Sgshapirosetclientoptions(p)
191064562Sgshapiro	register char *p;
191164562Sgshapiro{
191290792Sgshapiro	int family;
191390792Sgshapiro	DAEMON_T d;
191464562Sgshapiro
191564562Sgshapiro	memset(&d, '\0', sizeof d);
191664562Sgshapiro	setsockaddroptions(p, &d);
191764562Sgshapiro
191864562Sgshapiro	/* grab what we need */
191990792Sgshapiro	family = d.d_addr.sa.sa_family;
192090792Sgshapiro	STRUCTCOPY(d, ClientSettings[family]);
192190792Sgshapiro	setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */
192290792Sgshapiro	if (d.d_name != NULL)
192390792Sgshapiro		ClientSettings[family].d_name = newstr(d.d_name);
192464562Sgshapiro	else
192590792Sgshapiro	{
192690792Sgshapiro		char num[30];
192790792Sgshapiro
192890792Sgshapiro		(void) sm_snprintf(num, sizeof num, "Client%d", family);
192990792Sgshapiro		ClientSettings[family].d_name = newstr(num);
193090792Sgshapiro	}
193164562Sgshapiro}
193290792Sgshapiro/*
193364562Sgshapiro**  ADDR_FAMILY -- determine address family from address
193464562Sgshapiro**
193564562Sgshapiro**	Parameters:
193664562Sgshapiro**		addr -- the string representation of the address
193764562Sgshapiro**
193864562Sgshapiro**	Returns:
193964562Sgshapiro**		AF_INET, AF_INET6 or AF_UNSPEC
194064562Sgshapiro**
194164562Sgshapiro**	Side Effects:
194264562Sgshapiro**		none.
194364562Sgshapiro*/
194464562Sgshapiro
194564562Sgshapirostatic int
194664562Sgshapiroaddr_family(addr)
194764562Sgshapiro	char *addr;
194864562Sgshapiro{
194990792Sgshapiro#if NETINET6
195064562Sgshapiro	SOCKADDR clt_addr;
195190792Sgshapiro#endif /* NETINET6 */
195264562Sgshapiro
195390792Sgshapiro#if NETINET
195464562Sgshapiro	if (inet_addr(addr) != INADDR_NONE)
195564562Sgshapiro	{
195664562Sgshapiro		if (tTd(16, 9))
195790792Sgshapiro			sm_dprintf("addr_family(%s): INET\n", addr);
195864562Sgshapiro		return AF_INET;
195964562Sgshapiro	}
196090792Sgshapiro#endif /* NETINET */
196190792Sgshapiro#if NETINET6
196290792Sgshapiro	if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
196364562Sgshapiro	{
196464562Sgshapiro		if (tTd(16, 9))
196590792Sgshapiro			sm_dprintf("addr_family(%s): INET6\n", addr);
196664562Sgshapiro		return AF_INET6;
196764562Sgshapiro	}
196890792Sgshapiro#endif /* NETINET6 */
196990792Sgshapiro#if _FFR_DAEMON_NETUNIX
197090792Sgshapiro# if NETUNIX
197190792Sgshapiro	if (*addr == '/')
197290792Sgshapiro	{
197390792Sgshapiro		if (tTd(16, 9))
197490792Sgshapiro			sm_dprintf("addr_family(%s): LOCAL\n", addr);
197590792Sgshapiro		return AF_UNIX;
197690792Sgshapiro	}
197790792Sgshapiro# endif /* NETUNIX */
197890792Sgshapiro#endif	/* _FFR_DAEMON_NETUNIX */
197964562Sgshapiro	if (tTd(16, 9))
198090792Sgshapiro		sm_dprintf("addr_family(%s): UNSPEC\n", addr);
198164562Sgshapiro	return AF_UNSPEC;
198264562Sgshapiro}
198390792Sgshapiro
198490792Sgshapiro/*
198590792Sgshapiro**  CHKCLIENTMODIFIERS -- check whether all clients have set a flag.
198690792Sgshapiro**
198790792Sgshapiro**	Parameters:
198890792Sgshapiro**		flag -- the flag to test.
198990792Sgshapiro**
199090792Sgshapiro**	Returns:
199190792Sgshapiro**		true iff all configured clients have set the flag.
199290792Sgshapiro*/
199390792Sgshapiro
199490792Sgshapirobool
199590792Sgshapirochkclientmodifiers(flag)
199690792Sgshapiro	int flag;
199790792Sgshapiro{
199890792Sgshapiro	int i;
199990792Sgshapiro	bool flagisset;
200090792Sgshapiro
200190792Sgshapiro	flagisset = false;
200290792Sgshapiro	for (i = 0; i < AF_MAX; i++)
200390792Sgshapiro	{
200490792Sgshapiro		if (bitnset(D_ISSET, ClientSettings[i].d_flags))
200590792Sgshapiro		{
200690792Sgshapiro			if (!bitnset((char) flag, ClientSettings[i].d_flags))
200790792Sgshapiro				return false;
200890792Sgshapiro			flagisset = true;
200990792Sgshapiro		}
201090792Sgshapiro	}
201190792Sgshapiro	return flagisset;
201290792Sgshapiro}
201390792Sgshapiro
201490792Sgshapiro#if MILTER
201590792Sgshapiro/*
201690792Sgshapiro**  SETUP_DAEMON_FILTERS -- Parse per-socket filters
201790792Sgshapiro**
201890792Sgshapiro**	Parameters:
201990792Sgshapiro**		none
202090792Sgshapiro**
202190792Sgshapiro**	Returns:
202290792Sgshapiro**		none
202390792Sgshapiro*/
202490792Sgshapiro
202590792Sgshapirovoid
202690792Sgshapirosetup_daemon_milters()
202790792Sgshapiro{
202890792Sgshapiro	int idx;
202990792Sgshapiro
203090792Sgshapiro	if (OpMode == MD_SMTP)
203190792Sgshapiro	{
203290792Sgshapiro		/* no need to configure the daemons */
203390792Sgshapiro		return;
203490792Sgshapiro	}
203590792Sgshapiro
203690792Sgshapiro	for (idx = 0; idx < NDaemons; idx++)
203790792Sgshapiro	{
203890792Sgshapiro		if (Daemons[idx].d_inputfilterlist != NULL)
203990792Sgshapiro		{
204090792Sgshapiro			milter_config(Daemons[idx].d_inputfilterlist,
204190792Sgshapiro				      Daemons[idx].d_inputfilters,
204290792Sgshapiro				      MAXFILTERS);
204390792Sgshapiro		}
204490792Sgshapiro	}
204590792Sgshapiro}
204690792Sgshapiro#endif /* MILTER */
204790792Sgshapiro/*
204864562Sgshapiro**  MAKECONNECTION -- make a connection to an SMTP socket on a machine.
204964562Sgshapiro**
205064562Sgshapiro**	Parameters:
205138032Speter**		host -- the name of the host.
205238032Speter**		port -- the port number to connect to.
205338032Speter**		mci -- a pointer to the mail connection information
205438032Speter**			structure to be filled in.
205538032Speter**		e -- the current envelope.
205690792Sgshapiro**		enough -- time at which to stop further connection attempts.
205790792Sgshapiro**			(0 means no limit)
205838032Speter**
205938032Speter**	Returns:
206038032Speter**		An exit code telling whether the connection could be
206138032Speter**			made and if not why not.
206238032Speter**
206338032Speter**	Side Effects:
206438032Speter**		none.
206538032Speter*/
206638032Speter
206738032Speterstatic jmp_buf	CtxConnectTimeout;
206838032Speter
206938032SpeterSOCKADDR	CurHostAddr;		/* address of current host */
207038032Speter
207138032Speterint
207290792Sgshapiromakeconnection(host, port, mci, e, enough)
207338032Speter	char *host;
207490792Sgshapiro	volatile unsigned int port;
207538032Speter	register MCI *mci;
207638032Speter	ENVELOPE *e;
207790792Sgshapiro	time_t enough;
207838032Speter{
207938032Speter	register volatile int addrno = 0;
208090792Sgshapiro	volatile int s;
208190792Sgshapiro	register struct hostent *volatile hp = (struct hostent *) NULL;
208238032Speter	SOCKADDR addr;
208364562Sgshapiro	SOCKADDR clt_addr;
208464562Sgshapiro	int save_errno = 0;
208564562Sgshapiro	volatile SOCKADDR_LEN_T addrlen;
208638032Speter	volatile bool firstconnect;
208790792Sgshapiro	SM_EVENT *volatile ev = NULL;
208890792Sgshapiro#if NETINET6
208990792Sgshapiro	volatile bool v6found = false;
209090792Sgshapiro#endif /* NETINET6 */
209164562Sgshapiro	volatile int family = InetMode;
209264562Sgshapiro	SOCKADDR_LEN_T len;
209364562Sgshapiro	volatile SOCKADDR_LEN_T socksize = 0;
209464562Sgshapiro	volatile bool clt_bind;
209564562Sgshapiro	BITMAP256 d_flags;
209664562Sgshapiro	char *p;
209764562Sgshapiro	extern ENVELOPE BlankEnvelope;
209838032Speter
209990792Sgshapiro	/* retranslate {daemon_flags} into bitmap */
210064562Sgshapiro	clrbitmap(d_flags);
210190792Sgshapiro	if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL)
210264562Sgshapiro	{
210364562Sgshapiro		for (; *p != '\0'; p++)
210464562Sgshapiro		{
210564562Sgshapiro			if (!(isascii(*p) && isspace(*p)))
210671345Sgshapiro				setbitn(bitidx(*p), d_flags);
210764562Sgshapiro		}
210864562Sgshapiro	}
210964562Sgshapiro
211090792Sgshapiro#if NETINET6
211164562Sgshapiro v4retry:
211290792Sgshapiro#endif /* NETINET6 */
211390792Sgshapiro	clt_bind = false;
211464562Sgshapiro
211564562Sgshapiro	/* Set up the address for outgoing connection. */
211664562Sgshapiro	if (bitnset(D_BINDIF, d_flags) &&
211790792Sgshapiro	    (p = macvalue(macid("{if_addr}"), e)) != NULL &&
211873188Sgshapiro	    *p != '\0')
211964562Sgshapiro	{
212090792Sgshapiro#if NETINET6
212164562Sgshapiro		char p6[INET6_ADDRSTRLEN];
212290792Sgshapiro#endif /* NETINET6 */
212364562Sgshapiro
212464562Sgshapiro		memset(&clt_addr, '\0', sizeof clt_addr);
212564562Sgshapiro
212664562Sgshapiro		/* infer the address family from the address itself */
212764562Sgshapiro		clt_addr.sa.sa_family = addr_family(p);
212864562Sgshapiro		switch (clt_addr.sa.sa_family)
212964562Sgshapiro		{
213090792Sgshapiro#if NETINET
213164562Sgshapiro		  case AF_INET:
213273188Sgshapiro			clt_addr.sin.sin_addr.s_addr = inet_addr(p);
213373188Sgshapiro			if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE &&
213473188Sgshapiro			    clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK)
213564562Sgshapiro			{
213690792Sgshapiro				clt_bind = true;
213764562Sgshapiro				socksize = sizeof (struct sockaddr_in);
213864562Sgshapiro			}
213964562Sgshapiro			break;
214090792Sgshapiro#endif /* NETINET */
214164562Sgshapiro
214290792Sgshapiro#if NETINET6
214364562Sgshapiro		  case AF_INET6:
214464562Sgshapiro			if (inet_addr(p) != INADDR_NONE)
214590792Sgshapiro				(void) sm_snprintf(p6, sizeof p6,
214690792Sgshapiro						   "IPv6:::ffff:%s", p);
214764562Sgshapiro			else
214890792Sgshapiro				(void) sm_strlcpy(p6, p, sizeof p6);
214990792Sgshapiro			if (anynet_pton(AF_INET6, p6,
215090792Sgshapiro					&clt_addr.sin6.sin6_addr) == 1 &&
215173188Sgshapiro			    !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr))
215264562Sgshapiro			{
215390792Sgshapiro				clt_bind = true;
215464562Sgshapiro				socksize = sizeof (struct sockaddr_in6);
215564562Sgshapiro			}
215664562Sgshapiro			break;
215790792Sgshapiro#endif /* NETINET6 */
215864562Sgshapiro
215990792Sgshapiro#if 0
216064562Sgshapiro		  default:
216164562Sgshapiro			syserr("554 5.3.5 Address= option unsupported for family %d",
216264562Sgshapiro			       clt_addr.sa.sa_family);
216364562Sgshapiro			break;
216490792Sgshapiro#endif /* 0 */
216564562Sgshapiro		}
216664562Sgshapiro		if (clt_bind)
216764562Sgshapiro			family = clt_addr.sa.sa_family;
216864562Sgshapiro	}
216990792Sgshapiro
217090792Sgshapiro	/* D_BINDIF not set or not available, fallback to ClientPortOptions */
217190792Sgshapiro	if (!clt_bind)
217264562Sgshapiro	{
217390792Sgshapiro		STRUCTCOPY(ClientSettings[family].d_addr, clt_addr);
217464562Sgshapiro		switch (clt_addr.sa.sa_family)
217564562Sgshapiro		{
217690792Sgshapiro#if NETINET
217764562Sgshapiro		  case AF_INET:
217864562Sgshapiro			if (clt_addr.sin.sin_addr.s_addr == 0)
217964562Sgshapiro				clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
218064562Sgshapiro			else
218190792Sgshapiro				clt_bind = true;
218264562Sgshapiro			if (clt_addr.sin.sin_port != 0)
218390792Sgshapiro				clt_bind = true;
218464562Sgshapiro			socksize = sizeof (struct sockaddr_in);
218564562Sgshapiro			break;
218690792Sgshapiro#endif /* NETINET */
218790792Sgshapiro#if NETINET6
218864562Sgshapiro		  case AF_INET6:
218964562Sgshapiro			if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
219064562Sgshapiro				clt_addr.sin6.sin6_addr = in6addr_any;
219164562Sgshapiro			else
219290792Sgshapiro				clt_bind = true;
219364562Sgshapiro			socksize = sizeof (struct sockaddr_in6);
219464562Sgshapiro			if (clt_addr.sin6.sin6_port != 0)
219590792Sgshapiro				clt_bind = true;
219664562Sgshapiro			break;
219790792Sgshapiro#endif /* NETINET6 */
219890792Sgshapiro#if NETISO
219964562Sgshapiro		  case AF_ISO:
220064562Sgshapiro			socksize = sizeof clt_addr.siso;
220190792Sgshapiro			clt_bind = true;
220264562Sgshapiro			break;
220390792Sgshapiro#endif /* NETISO */
220464562Sgshapiro		  default:
220564562Sgshapiro			break;
220664562Sgshapiro		}
220764562Sgshapiro	}
220864562Sgshapiro
220938032Speter	/*
221038032Speter	**  Set up the address for the mailer.
221138032Speter	**	Accept "[a.b.c.d]" syntax for host name.
221238032Speter	*/
221338032Speter
221473188Sgshapiro	SM_SET_H_ERRNO(0);
221538032Speter	errno = 0;
221664562Sgshapiro	memset(&CurHostAddr, '\0', sizeof CurHostAddr);
221764562Sgshapiro	memset(&addr, '\0', sizeof addr);
221838032Speter	SmtpPhase = mci->mci_phase = "initial connection";
221938032Speter	CurHostName = host;
222038032Speter
222138032Speter	if (host[0] == '[')
222238032Speter	{
222364562Sgshapiro		p = strchr(host, ']');
222438032Speter		if (p != NULL)
222538032Speter		{
222690792Sgshapiro#if NETINET
222764562Sgshapiro			unsigned long hid = INADDR_NONE;
222890792Sgshapiro#endif /* NETINET */
222990792Sgshapiro#if NETINET6
223064562Sgshapiro			struct sockaddr_in6 hid6;
223190792Sgshapiro#endif /* NETINET6 */
223264562Sgshapiro
223338032Speter			*p = '\0';
223490792Sgshapiro#if NETINET6
223564562Sgshapiro			memset(&hid6, '\0', sizeof hid6);
223690792Sgshapiro#endif /* NETINET6 */
223790792Sgshapiro#if NETINET
223864562Sgshapiro			if (family == AF_INET &&
223964562Sgshapiro			    (hid = inet_addr(&host[1])) != INADDR_NONE)
224038032Speter			{
224164562Sgshapiro				addr.sin.sin_family = AF_INET;
224264562Sgshapiro				addr.sin.sin_addr.s_addr = hid;
224364562Sgshapiro			}
224464562Sgshapiro			else
224590792Sgshapiro#endif /* NETINET */
224690792Sgshapiro#if NETINET6
224764562Sgshapiro			if (family == AF_INET6 &&
224890792Sgshapiro			    anynet_pton(AF_INET6, &host[1],
224990792Sgshapiro					&hid6.sin6_addr) == 1)
225064562Sgshapiro			{
225164562Sgshapiro				addr.sin6.sin6_family = AF_INET6;
225264562Sgshapiro				addr.sin6.sin6_addr = hid6.sin6_addr;
225364562Sgshapiro			}
225464562Sgshapiro			else
225590792Sgshapiro#endif /* NETINET6 */
225664562Sgshapiro			{
225738032Speter				/* try it as a host name (avoid MX lookup) */
225864562Sgshapiro				hp = sm_gethostbyname(&host[1], family);
225938032Speter				if (hp == NULL && p[-1] == '.')
226038032Speter				{
226190792Sgshapiro#if NAMED_BIND
226238032Speter					int oldopts = _res.options;
226338032Speter
226438032Speter					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
226590792Sgshapiro#endif /* NAMED_BIND */
226638032Speter					p[-1] = '\0';
226764562Sgshapiro					hp = sm_gethostbyname(&host[1],
226864562Sgshapiro							      family);
226938032Speter					p[-1] = '.';
227090792Sgshapiro#if NAMED_BIND
227138032Speter					_res.options = oldopts;
227290792Sgshapiro#endif /* NAMED_BIND */
227338032Speter				}
227438032Speter				*p = ']';
227538032Speter				goto gothostent;
227638032Speter			}
227738032Speter			*p = ']';
227838032Speter		}
227938032Speter		if (p == NULL)
228038032Speter		{
228138032Speter			extern char MsgBuf[];
228238032Speter
228364562Sgshapiro			usrerrenh("5.1.2",
228464562Sgshapiro				  "553 Invalid numeric domain spec \"%s\"",
228564562Sgshapiro				  host);
228638032Speter			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
228764562Sgshapiro			errno = EINVAL;
228838032Speter			return EX_NOHOST;
228938032Speter		}
229038032Speter	}
229138032Speter	else
229238032Speter	{
229338032Speter		/* contortion to get around SGI cc complaints */
229438032Speter		{
229564562Sgshapiro			p = &host[strlen(host) - 1];
229664562Sgshapiro			hp = sm_gethostbyname(host, family);
229738032Speter			if (hp == NULL && *p == '.')
229838032Speter			{
229990792Sgshapiro#if NAMED_BIND
230038032Speter				int oldopts = _res.options;
230138032Speter
230238032Speter				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
230390792Sgshapiro#endif /* NAMED_BIND */
230438032Speter				*p = '\0';
230564562Sgshapiro				hp = sm_gethostbyname(host, family);
230638032Speter				*p = '.';
230790792Sgshapiro#if NAMED_BIND
230838032Speter				_res.options = oldopts;
230990792Sgshapiro#endif /* NAMED_BIND */
231038032Speter			}
231138032Speter		}
231238032Spetergothostent:
231338032Speter		if (hp == NULL)
231438032Speter		{
231590792Sgshapiro#if NAMED_BIND
231638032Speter			/* check for name server timeouts */
231790792Sgshapiro# if NETINET6
231890792Sgshapiro			if (WorkAroundBrokenAAAA && family == AF_INET6 &&
231990792Sgshapiro			    errno == ETIMEDOUT)
232038032Speter			{
232190792Sgshapiro				/*
232290792Sgshapiro				**  An attempt with family AF_INET may
232390792Sgshapiro				**  succeed By skipping the next section
232490792Sgshapiro				**  of code, we will try AF_INET before
232590792Sgshapiro				**  failing.
232690792Sgshapiro				*/
232790792Sgshapiro
232890792Sgshapiro				if (tTd(16, 10))
232990792Sgshapiro					sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n");
233038032Speter			}
233190792Sgshapiro			else
233290792Sgshapiro# endif /* NETINET6 */
233390792Sgshapiro			{
233490792Sgshapiro				if (errno == ETIMEDOUT ||
233590792Sgshapiro				    h_errno == TRY_AGAIN ||
233690792Sgshapiro				    (errno == ECONNREFUSED && UseNameServer))
233790792Sgshapiro				{
233890792Sgshapiro					save_errno = errno;
233990792Sgshapiro					mci_setstat(mci, EX_TEMPFAIL,
234090792Sgshapiro						    "4.4.3", NULL);
234190792Sgshapiro					errno = save_errno;
234290792Sgshapiro					return EX_TEMPFAIL;
234390792Sgshapiro				}
234490792Sgshapiro			}
234590792Sgshapiro#endif /* NAMED_BIND */
234690792Sgshapiro#if NETINET6
234764562Sgshapiro			/*
234864562Sgshapiro			**  Try v6 first, then fall back to v4.
234964562Sgshapiro			**  If we found a v6 address, but no v4
235064562Sgshapiro			**  addresses, then TEMPFAIL.
235164562Sgshapiro			*/
235264562Sgshapiro
235364562Sgshapiro			if (family == AF_INET6)
235464562Sgshapiro			{
235564562Sgshapiro				family = AF_INET;
235664562Sgshapiro				goto v4retry;
235764562Sgshapiro			}
235864562Sgshapiro			if (v6found)
235964562Sgshapiro				goto v6tempfail;
236090792Sgshapiro#endif /* NETINET6 */
236164562Sgshapiro			save_errno = errno;
236238032Speter			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
236364562Sgshapiro			errno = save_errno;
236464562Sgshapiro			return EX_NOHOST;
236538032Speter		}
236638032Speter		addr.sa.sa_family = hp->h_addrtype;
236738032Speter		switch (hp->h_addrtype)
236838032Speter		{
236990792Sgshapiro#if NETINET
237038032Speter		  case AF_INET:
237164562Sgshapiro			memmove(&addr.sin.sin_addr,
237264562Sgshapiro				hp->h_addr,
237338032Speter				INADDRSZ);
237438032Speter			break;
237590792Sgshapiro#endif /* NETINET */
237638032Speter
237790792Sgshapiro#if NETINET6
237864562Sgshapiro		  case AF_INET6:
237964562Sgshapiro			memmove(&addr.sin6.sin6_addr,
238064562Sgshapiro				hp->h_addr,
238164562Sgshapiro				IN6ADDRSZ);
238264562Sgshapiro			break;
238390792Sgshapiro#endif /* NETINET6 */
238464562Sgshapiro
238538032Speter		  default:
238638032Speter			if (hp->h_length > sizeof addr.sa.sa_data)
238738032Speter			{
238838032Speter				syserr("makeconnection: long sa_data: family %d len %d",
238938032Speter					hp->h_addrtype, hp->h_length);
239038032Speter				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
239164562Sgshapiro				errno = EINVAL;
239238032Speter				return EX_NOHOST;
239338032Speter			}
239490792Sgshapiro			memmove(addr.sa.sa_data, hp->h_addr, hp->h_length);
239538032Speter			break;
239638032Speter		}
239738032Speter		addrno = 1;
239838032Speter	}
239938032Speter
240038032Speter	/*
240138032Speter	**  Determine the port number.
240238032Speter	*/
240338032Speter
240438032Speter	if (port == 0)
240538032Speter	{
240690792Sgshapiro#ifdef NO_GETSERVBYNAME
240764562Sgshapiro		port = htons(25);
240890792Sgshapiro#else /* NO_GETSERVBYNAME */
240938032Speter		register struct servent *sp = getservbyname("smtp", "tcp");
241038032Speter
241138032Speter		if (sp == NULL)
241238032Speter		{
241338032Speter			if (LogLevel > 2)
241438032Speter				sm_syslog(LOG_ERR, NOQID,
241564562Sgshapiro					  "makeconnection: service \"smtp\" unknown");
241638032Speter			port = htons(25);
241738032Speter		}
241838032Speter		else
241938032Speter			port = sp->s_port;
242090792Sgshapiro#endif /* NO_GETSERVBYNAME */
242138032Speter	}
242238032Speter
242390792Sgshapiro#if NETINET6
242490792Sgshapiro	if (addr.sa.sa_family == AF_INET6 &&
242590792Sgshapiro	    IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) &&
242690792Sgshapiro	    ClientSettings[AF_INET].d_addr.sa.sa_family != 0)
242790792Sgshapiro	{
242890792Sgshapiro		/*
242990792Sgshapiro		**  Ignore mapped IPv4 address since
243090792Sgshapiro		**  there is a ClientPortOptions setting
243190792Sgshapiro		**  for IPv4.
243290792Sgshapiro		*/
243390792Sgshapiro
243490792Sgshapiro		goto nextaddr;
243590792Sgshapiro	}
243690792Sgshapiro#endif /* NETINET6 */
243790792Sgshapiro
243838032Speter	switch (addr.sa.sa_family)
243938032Speter	{
244090792Sgshapiro#if NETINET
244138032Speter	  case AF_INET:
244238032Speter		addr.sin.sin_port = port;
244338032Speter		addrlen = sizeof (struct sockaddr_in);
244438032Speter		break;
244590792Sgshapiro#endif /* NETINET */
244638032Speter
244790792Sgshapiro#if NETINET6
244864562Sgshapiro	  case AF_INET6:
244964562Sgshapiro		addr.sin6.sin6_port = port;
245064562Sgshapiro		addrlen = sizeof (struct sockaddr_in6);
245164562Sgshapiro		break;
245290792Sgshapiro#endif /* NETINET6 */
245364562Sgshapiro
245490792Sgshapiro#if NETISO
245538032Speter	  case AF_ISO:
245638032Speter		/* assume two byte transport selector */
245764562Sgshapiro		memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
245838032Speter		addrlen = sizeof (struct sockaddr_iso);
245938032Speter		break;
246090792Sgshapiro#endif /* NETISO */
246138032Speter
246238032Speter	  default:
246338032Speter		syserr("Can't connect to address family %d", addr.sa.sa_family);
246438032Speter		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
246564562Sgshapiro		errno = EINVAL;
246690792Sgshapiro#if NETINET6
246771345Sgshapiro		if (hp != NULL)
246871345Sgshapiro			freehostent(hp);
246990792Sgshapiro#endif /* NETINET6 */
247064562Sgshapiro		return EX_NOHOST;
247138032Speter	}
247238032Speter
247338032Speter	/*
247438032Speter	**  Try to actually open the connection.
247538032Speter	*/
247638032Speter
247790792Sgshapiro#if XLA
247838032Speter	/* if too many connections, don't bother trying */
247938032Speter	if (!xla_noqueue_ok(host))
248071345Sgshapiro	{
248190792Sgshapiro# if NETINET6
248271345Sgshapiro		if (hp != NULL)
248371345Sgshapiro			freehostent(hp);
248490792Sgshapiro# endif /* NETINET6 */
248538032Speter		return EX_TEMPFAIL;
248671345Sgshapiro	}
248790792Sgshapiro#endif /* XLA */
248838032Speter
248990792Sgshapiro	firstconnect = true;
249038032Speter	for (;;)
249138032Speter	{
249238032Speter		if (tTd(16, 1))
249390792Sgshapiro			sm_dprintf("makeconnection (%s [%s].%d (%d))\n",
249490792Sgshapiro				   host, anynet_ntoa(&addr), ntohs(port),
249590792Sgshapiro				   (int) addr.sa.sa_family);
249638032Speter
249738032Speter		/* save for logging */
249838032Speter		CurHostAddr = addr;
249938032Speter
250090792Sgshapiro#if HASRRESVPORT
250138032Speter		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
250238032Speter		{
250338032Speter			int rport = IPPORT_RESERVED - 1;
250438032Speter
250538032Speter			s = rresvport(&rport);
250638032Speter		}
250738032Speter		else
250890792Sgshapiro#endif /* HASRRESVPORT */
250938032Speter		{
251090792Sgshapiro			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
251138032Speter		}
251238032Speter		if (s < 0)
251338032Speter		{
251464562Sgshapiro			save_errno = errno;
251538032Speter			syserr("makeconnection: cannot create socket");
251690792Sgshapiro#if XLA
251738032Speter			xla_host_end(host);
251890792Sgshapiro#endif /* XLA */
251938032Speter			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
252090792Sgshapiro#if NETINET6
252171345Sgshapiro			if (hp != NULL)
252271345Sgshapiro				freehostent(hp);
252390792Sgshapiro#endif /* NETINET6 */
252464562Sgshapiro			errno = save_errno;
252538032Speter			return EX_TEMPFAIL;
252638032Speter		}
252738032Speter
252890792Sgshapiro#ifdef SO_SNDBUF
252990792Sgshapiro		if (ClientSettings[family].d_tcpsndbufsize > 0)
253038032Speter		{
253138032Speter			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
253290792Sgshapiro				       (char *) &ClientSettings[family].d_tcpsndbufsize,
253390792Sgshapiro				       sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0)
253438032Speter				syserr("makeconnection: setsockopt(SO_SNDBUF)");
253538032Speter		}
253690792Sgshapiro#endif /* SO_SNDBUF */
253790792Sgshapiro#ifdef SO_RCVBUF
253890792Sgshapiro		if (ClientSettings[family].d_tcprcvbufsize > 0)
253964562Sgshapiro		{
254064562Sgshapiro			if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
254190792Sgshapiro				       (char *) &ClientSettings[family].d_tcprcvbufsize,
254290792Sgshapiro				       sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0)
254364562Sgshapiro				syserr("makeconnection: setsockopt(SO_RCVBUF)");
254464562Sgshapiro		}
254590792Sgshapiro#endif /* SO_RCVBUF */
254638032Speter
254738032Speter		if (tTd(16, 1))
254890792Sgshapiro			sm_dprintf("makeconnection: fd=%d\n", s);
254938032Speter
255038032Speter		/* turn on network debugging? */
255138032Speter		if (tTd(16, 101))
255238032Speter		{
255338032Speter			int on = 1;
255464562Sgshapiro
255538032Speter			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
255638032Speter					  (char *)&on, sizeof on);
255738032Speter		}
255890792Sgshapiro		if (e->e_xfp != NULL)	/* for debugging */
255990792Sgshapiro			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
256090792Sgshapiro		errno = 0;		/* for debugging */
256138032Speter
256264562Sgshapiro		if (clt_bind)
256364562Sgshapiro		{
256464562Sgshapiro			int on = 1;
256564562Sgshapiro
256664562Sgshapiro			switch (clt_addr.sa.sa_family)
256764562Sgshapiro			{
256890792Sgshapiro#if NETINET
256964562Sgshapiro			  case AF_INET:
257064562Sgshapiro				if (clt_addr.sin.sin_port != 0)
257164562Sgshapiro					(void) setsockopt(s, SOL_SOCKET,
257264562Sgshapiro							  SO_REUSEADDR,
257364562Sgshapiro							  (char *) &on,
257464562Sgshapiro							  sizeof on);
257564562Sgshapiro				break;
257690792Sgshapiro#endif /* NETINET */
257764562Sgshapiro
257890792Sgshapiro#if NETINET6
257964562Sgshapiro			  case AF_INET6:
258064562Sgshapiro				if (clt_addr.sin6.sin6_port != 0)
258164562Sgshapiro					(void) setsockopt(s, SOL_SOCKET,
258264562Sgshapiro							  SO_REUSEADDR,
258364562Sgshapiro							  (char *) &on,
258464562Sgshapiro							  sizeof on);
258564562Sgshapiro				break;
258690792Sgshapiro#endif /* NETINET6 */
258764562Sgshapiro			}
258864562Sgshapiro
258964562Sgshapiro			if (bind(s, &clt_addr.sa, socksize) < 0)
259064562Sgshapiro			{
259164562Sgshapiro				save_errno = errno;
259264562Sgshapiro				(void) close(s);
259364562Sgshapiro				errno = save_errno;
259464562Sgshapiro				syserr("makeconnection: cannot bind socket [%s]",
259564562Sgshapiro				       anynet_ntoa(&clt_addr));
259690792Sgshapiro#if NETINET6
259771345Sgshapiro				if (hp != NULL)
259871345Sgshapiro					freehostent(hp);
259990792Sgshapiro#endif /* NETINET6 */
260064562Sgshapiro				errno = save_errno;
260164562Sgshapiro				return EX_TEMPFAIL;
260264562Sgshapiro			}
260364562Sgshapiro		}
260464562Sgshapiro
260538032Speter		/*
260638032Speter		**  Linux seems to hang in connect for 90 minutes (!!!).
260738032Speter		**  Time out the connect to avoid this problem.
260838032Speter		*/
260938032Speter
261038032Speter		if (setjmp(CtxConnectTimeout) == 0)
261138032Speter		{
261238032Speter			int i;
261338032Speter
261438032Speter			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
261590792Sgshapiro				ev = sm_setevent(TimeOuts.to_iconnect,
261690792Sgshapiro						 connecttimeout, 0);
261738032Speter			else if (TimeOuts.to_connect != 0)
261890792Sgshapiro				ev = sm_setevent(TimeOuts.to_connect,
261990792Sgshapiro						 connecttimeout, 0);
262038032Speter			else
262138032Speter				ev = NULL;
262238032Speter
262364562Sgshapiro			switch (ConnectOnlyTo.sa.sa_family)
262464562Sgshapiro			{
262590792Sgshapiro#if NETINET
262664562Sgshapiro			  case AF_INET:
262764562Sgshapiro				addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
262864562Sgshapiro				break;
262990792Sgshapiro#endif /* NETINET */
263064562Sgshapiro
263190792Sgshapiro#if NETINET6
263264562Sgshapiro			  case AF_INET6:
263364562Sgshapiro				memmove(&addr.sin6.sin6_addr,
263464562Sgshapiro					&ConnectOnlyTo.sin6.sin6_addr,
263564562Sgshapiro					IN6ADDRSZ);
263664562Sgshapiro				break;
263790792Sgshapiro#endif /* NETINET6 */
263864562Sgshapiro			}
2639141858Sgshapiro			if (tTd(16, 1))
2640141858Sgshapiro				sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr));
264138032Speter			i = connect(s, (struct sockaddr *) &addr, addrlen);
264264562Sgshapiro			save_errno = errno;
264338032Speter			if (ev != NULL)
264490792Sgshapiro				sm_clrevent(ev);
264538032Speter			if (i >= 0)
264638032Speter				break;
264738032Speter		}
264838032Speter		else
264964562Sgshapiro			save_errno = errno;
265038032Speter
265194334Sgshapiro		/* couldn't connect.... figure out why */
265294334Sgshapiro		(void) close(s);
265394334Sgshapiro
265438032Speter		/* if running demand-dialed connection, try again */
265590792Sgshapiro		if (DialDelay > 0 && firstconnect &&
265690792Sgshapiro		    bitnset(M_DIALDELAY, mci->mci_mailer->m_flags))
265738032Speter		{
265838032Speter			if (tTd(16, 1))
265990792Sgshapiro				sm_dprintf("Connect failed (%s); trying again...\n",
266090792Sgshapiro					   sm_errstring(save_errno));
266190792Sgshapiro			firstconnect = false;
266264562Sgshapiro			(void) sleep(DialDelay);
266338032Speter			continue;
266438032Speter		}
266538032Speter
266690792Sgshapiro		if (LogLevel > 13)
266738032Speter			sm_syslog(LOG_INFO, e->e_id,
266838032Speter				  "makeconnection (%s [%s]) failed: %s",
266938032Speter				  host, anynet_ntoa(&addr),
267090792Sgshapiro				  sm_errstring(save_errno));
267138032Speter
267290792Sgshapiro#if NETINET6
267390792Sgshapironextaddr:
267490792Sgshapiro#endif /* NETINET6 */
267590792Sgshapiro		if (hp != NULL && hp->h_addr_list[addrno] != NULL &&
267690792Sgshapiro		    (enough == 0 || curtime() < enough))
267738032Speter		{
267838032Speter			if (tTd(16, 1))
267990792Sgshapiro				sm_dprintf("Connect failed (%s); trying new address....\n",
268090792Sgshapiro					   sm_errstring(save_errno));
268138032Speter			switch (addr.sa.sa_family)
268238032Speter			{
268390792Sgshapiro#if NETINET
268438032Speter			  case AF_INET:
268564562Sgshapiro				memmove(&addr.sin.sin_addr,
268664562Sgshapiro					hp->h_addr_list[addrno++],
268764562Sgshapiro					INADDRSZ);
268838032Speter				break;
268990792Sgshapiro#endif /* NETINET */
269038032Speter
269190792Sgshapiro#if NETINET6
269264562Sgshapiro			  case AF_INET6:
269364562Sgshapiro				memmove(&addr.sin6.sin6_addr,
269464562Sgshapiro					hp->h_addr_list[addrno++],
269564562Sgshapiro					IN6ADDRSZ);
269664562Sgshapiro				break;
269790792Sgshapiro#endif /* NETINET6 */
269864562Sgshapiro
269938032Speter			  default:
270064562Sgshapiro				memmove(addr.sa.sa_data,
270164562Sgshapiro					hp->h_addr_list[addrno++],
270238032Speter					hp->h_length);
270338032Speter				break;
270438032Speter			}
270538032Speter			continue;
270638032Speter		}
270764562Sgshapiro		errno = save_errno;
270838032Speter
270990792Sgshapiro#if NETINET6
271064562Sgshapiro		if (family == AF_INET6)
271164562Sgshapiro		{
271264562Sgshapiro			if (tTd(16, 1))
271390792Sgshapiro				sm_dprintf("Connect failed (%s); retrying with AF_INET....\n",
271490792Sgshapiro					   sm_errstring(save_errno));
271590792Sgshapiro			v6found = true;
271664562Sgshapiro			family = AF_INET;
271771345Sgshapiro			if (hp != NULL)
271871345Sgshapiro			{
271971345Sgshapiro				freehostent(hp);
272071345Sgshapiro				hp = NULL;
272171345Sgshapiro			}
272264562Sgshapiro			goto v4retry;
272364562Sgshapiro		}
272464562Sgshapiro	v6tempfail:
272590792Sgshapiro#endif /* NETINET6 */
272638032Speter		/* couldn't open connection */
272790792Sgshapiro#if NETINET6
272864562Sgshapiro		/* Don't clobber an already saved errno from v4retry */
272964562Sgshapiro		if (errno > 0)
273090792Sgshapiro#endif /* NETINET6 */
273164562Sgshapiro			save_errno = errno;
273264562Sgshapiro		if (tTd(16, 1))
273390792Sgshapiro			sm_dprintf("Connect failed (%s)\n",
273490792Sgshapiro				   sm_errstring(save_errno));
273590792Sgshapiro#if XLA
273638032Speter		xla_host_end(host);
273790792Sgshapiro#endif /* XLA */
273838032Speter		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
273990792Sgshapiro#if NETINET6
274071345Sgshapiro		if (hp != NULL)
274171345Sgshapiro			freehostent(hp);
274290792Sgshapiro#endif /* NETINET6 */
274364562Sgshapiro		errno = save_errno;
274438032Speter		return EX_TEMPFAIL;
274538032Speter	}
274638032Speter
274790792Sgshapiro#if NETINET6
274871345Sgshapiro	if (hp != NULL)
274971345Sgshapiro	{
275071345Sgshapiro		freehostent(hp);
275171345Sgshapiro		hp = NULL;
275271345Sgshapiro	}
275390792Sgshapiro#endif /* NETINET6 */
275471345Sgshapiro
275538032Speter	/* connection ok, put it into canonical form */
275664562Sgshapiro	mci->mci_out = NULL;
275790792Sgshapiro	if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
275890792Sgshapiro				       (void *) &s,
2759132943Sgshapiro				       SM_IO_WRONLY_B, NULL)) == NULL ||
276038032Speter	    (s = dup(s)) < 0 ||
276190792Sgshapiro	    (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
276290792Sgshapiro				      (void *) &s,
2763132943Sgshapiro				      SM_IO_RDONLY_B, NULL)) == NULL)
276438032Speter	{
276564562Sgshapiro		save_errno = errno;
276638032Speter		syserr("cannot open SMTP client channel, fd=%d", s);
276738032Speter		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
276864562Sgshapiro		if (mci->mci_out != NULL)
276990792Sgshapiro			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
277064562Sgshapiro		(void) close(s);
277164562Sgshapiro		errno = save_errno;
277238032Speter		return EX_TEMPFAIL;
277338032Speter	}
277490792Sgshapiro	sm_io_automode(mci->mci_out, mci->mci_in);
277538032Speter
277690792Sgshapiro	/* set {client_flags} */
277790792Sgshapiro	if (ClientSettings[addr.sa.sa_family].d_mflags != NULL)
277890792Sgshapiro	{
277990792Sgshapiro		macdefine(&mci->mci_macro, A_PERM,
278090792Sgshapiro			  macid("{client_flags}"),
278190792Sgshapiro			  ClientSettings[addr.sa.sa_family].d_mflags);
278290792Sgshapiro	}
278390792Sgshapiro	else
278490792Sgshapiro		macdefine(&mci->mci_macro, A_PERM,
278590792Sgshapiro			  macid("{client_flags}"), "");
278690792Sgshapiro
278790792Sgshapiro	/* "add" {client_flags} to bitmap */
278890792Sgshapiro	if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags))
278990792Sgshapiro	{
279090792Sgshapiro		/* look for just this one flag */
279190792Sgshapiro		setbitn(D_IFNHELO, d_flags);
279290792Sgshapiro	}
279390792Sgshapiro
279464562Sgshapiro	/* find out name for Interface through which we connect */
279564562Sgshapiro	len = sizeof addr;
279664562Sgshapiro	if (getsockname(s, &addr.sa, &len) == 0)
279764562Sgshapiro	{
279864562Sgshapiro		char *name;
279990792Sgshapiro		char family[5];
280064562Sgshapiro
280190792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_TEMP,
280290792Sgshapiro			macid("{if_addr_out}"), anynet_ntoa(&addr));
280390792Sgshapiro		(void) sm_snprintf(family, sizeof(family), "%d",
280490792Sgshapiro			addr.sa.sa_family);
280590792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_TEMP,
280690792Sgshapiro			macid("{if_family_out}"), family);
280764562Sgshapiro
280864562Sgshapiro		name = hostnamebyanyaddr(&addr);
280990792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_TEMP,
281090792Sgshapiro			macid("{if_name_out}"), name);
281164562Sgshapiro		if (LogLevel > 11)
281264562Sgshapiro		{
281364562Sgshapiro			/* log connection information */
281464562Sgshapiro			sm_syslog(LOG_INFO, e->e_id,
281564562Sgshapiro				  "SMTP outgoing connect on %.40s", name);
281664562Sgshapiro		}
281764562Sgshapiro		if (bitnset(D_IFNHELO, d_flags))
281864562Sgshapiro		{
281964562Sgshapiro			if (name[0] != '[' && strchr(name, '.') != NULL)
282064562Sgshapiro				mci->mci_heloname = newstr(name);
282164562Sgshapiro		}
282264562Sgshapiro	}
282364562Sgshapiro	else
282464562Sgshapiro	{
282590792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_PERM,
282690792Sgshapiro			macid("{if_name_out}"), NULL);
282790792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_PERM,
282890792Sgshapiro			macid("{if_addr_out}"), NULL);
282990792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_PERM,
283090792Sgshapiro			macid("{if_family_out}"), NULL);
283164562Sgshapiro	}
2832132943Sgshapiro
2833132943Sgshapiro#if _FFR_HELONAME
2834132943Sgshapiro	/* Use the configured HeloName as appropriate */
2835132943Sgshapiro	if (HeloName != NULL && HeloName[0] != '\0')
2836132943Sgshapiro		mci->mci_heloname = newstr(HeloName);
2837132943Sgshapiro#endif /* _FFR_HELONAME */
2838132943Sgshapiro
283938032Speter	mci_setstat(mci, EX_OK, NULL, NULL);
284064562Sgshapiro	return EX_OK;
284138032Speter}
284264562Sgshapiro
284364562Sgshapirostatic void
2844141858Sgshapiroconnecttimeout(ignore)
2845141858Sgshapiro	int ignore;
284664562Sgshapiro{
284777349Sgshapiro	/*
284877349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
284977349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
285077349Sgshapiro	**	DOING.
285177349Sgshapiro	*/
285277349Sgshapiro
285364562Sgshapiro	errno = ETIMEDOUT;
285464562Sgshapiro	longjmp(CtxConnectTimeout, 1);
285564562Sgshapiro}
285690792Sgshapiro/*
285764562Sgshapiro**  MAKECONNECTION_DS -- make a connection to a domain socket.
285864562Sgshapiro**
285964562Sgshapiro**	Parameters:
286064562Sgshapiro**		mux_path -- the path of the socket to connect to.
286164562Sgshapiro**		mci -- a pointer to the mail connection information
286264562Sgshapiro**			structure to be filled in.
286364562Sgshapiro**
286464562Sgshapiro**	Returns:
286564562Sgshapiro**		An exit code telling whether the connection could be
286664562Sgshapiro**			made and if not why not.
286764562Sgshapiro**
286864562Sgshapiro**	Side Effects:
286964562Sgshapiro**		none.
287064562Sgshapiro*/
287164562Sgshapiro
287290792Sgshapiro#if NETUNIX
287390792Sgshapiroint
287490792Sgshapiromakeconnection_ds(mux_path, mci)
287564562Sgshapiro	char *mux_path;
287664562Sgshapiro	register MCI *mci;
287764562Sgshapiro{
287864562Sgshapiro	int sock;
287964562Sgshapiro	int rval, save_errno;
288064562Sgshapiro	long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
288164562Sgshapiro	struct sockaddr_un unix_addr;
288264562Sgshapiro
288364562Sgshapiro	/* if not safe, don't connect */
288464562Sgshapiro	rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
288564562Sgshapiro			sff, S_IRUSR|S_IWUSR, NULL);
288664562Sgshapiro
288764562Sgshapiro	if (rval != 0)
288864562Sgshapiro	{
2889132943Sgshapiro		syserr("makeconnection_ds: unsafe domain socket %s",
2890132943Sgshapiro			mux_path);
289164562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
289264562Sgshapiro		errno = rval;
289364562Sgshapiro		return EX_TEMPFAIL;
289464562Sgshapiro	}
289564562Sgshapiro
289664562Sgshapiro	/* prepare address structure */
289764562Sgshapiro	memset(&unix_addr, '\0', sizeof unix_addr);
289864562Sgshapiro	unix_addr.sun_family = AF_UNIX;
289964562Sgshapiro
290064562Sgshapiro	if (strlen(mux_path) >= sizeof unix_addr.sun_path)
290164562Sgshapiro	{
2902132943Sgshapiro		syserr("makeconnection_ds: domain socket name %s too long",
2903132943Sgshapiro			mux_path);
290490792Sgshapiro
290590792Sgshapiro		/* XXX why TEMPFAIL but 5.x.y ? */
290664562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
290764562Sgshapiro		errno = ENAMETOOLONG;
290864562Sgshapiro		return EX_UNAVAILABLE;
290964562Sgshapiro	}
291090792Sgshapiro	(void) sm_strlcpy(unix_addr.sun_path, mux_path,
291190792Sgshapiro			  sizeof unix_addr.sun_path);
291264562Sgshapiro
291364562Sgshapiro	/* initialize domain socket */
291464562Sgshapiro	sock = socket(AF_UNIX, SOCK_STREAM, 0);
291564562Sgshapiro	if (sock == -1)
291664562Sgshapiro	{
291764562Sgshapiro		save_errno = errno;
2918132943Sgshapiro		syserr("makeconnection_ds: could not create domain socket %s",
2919132943Sgshapiro			mux_path);
292064562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
292164562Sgshapiro		errno = save_errno;
292264562Sgshapiro		return EX_TEMPFAIL;
292364562Sgshapiro	}
292464562Sgshapiro
292564562Sgshapiro	/* connect to server */
292664562Sgshapiro	if (connect(sock, (struct sockaddr *) &unix_addr,
292764562Sgshapiro		    sizeof(unix_addr)) == -1)
292864562Sgshapiro	{
292964562Sgshapiro		save_errno = errno;
293064562Sgshapiro		syserr("Could not connect to socket %s", mux_path);
293164562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
293264562Sgshapiro		(void) close(sock);
293364562Sgshapiro		errno = save_errno;
293464562Sgshapiro		return EX_TEMPFAIL;
293564562Sgshapiro	}
293664562Sgshapiro
293764562Sgshapiro	/* connection ok, put it into canonical form */
293864562Sgshapiro	mci->mci_out = NULL;
293990792Sgshapiro	if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2940132943Sgshapiro				       (void *) &sock, SM_IO_WRONLY_B, NULL))
294190792Sgshapiro					== NULL
294290792Sgshapiro	    || (sock = dup(sock)) < 0 ||
294390792Sgshapiro	    (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2944132943Sgshapiro				      (void *) &sock, SM_IO_RDONLY_B, NULL))
294590792Sgshapiro					== NULL)
294664562Sgshapiro	{
294764562Sgshapiro		save_errno = errno;
294864562Sgshapiro		syserr("cannot open SMTP client channel, fd=%d", sock);
294964562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
295064562Sgshapiro		if (mci->mci_out != NULL)
295190792Sgshapiro			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
295264562Sgshapiro		(void) close(sock);
295364562Sgshapiro		errno = save_errno;
295464562Sgshapiro		return EX_TEMPFAIL;
295564562Sgshapiro	}
295690792Sgshapiro	sm_io_automode(mci->mci_out, mci->mci_in);
295764562Sgshapiro
295864562Sgshapiro	mci_setstat(mci, EX_OK, NULL, NULL);
295964562Sgshapiro	errno = 0;
296064562Sgshapiro	return EX_OK;
296164562Sgshapiro}
296290792Sgshapiro#endif /* NETUNIX */
296390792Sgshapiro/*
296490792Sgshapiro**  SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
296577349Sgshapiro**
296677349Sgshapiro**	Parameters:
296790792Sgshapiro**		none.
296877349Sgshapiro**
296977349Sgshapiro**	Returns:
297077349Sgshapiro**		none.
297177349Sgshapiro**
297277349Sgshapiro**	Side Effects:
297390792Sgshapiro**		closes control socket, exits.
297477349Sgshapiro*/
297577349Sgshapiro
297690792Sgshapirovoid
297790792Sgshapiroshutdown_daemon()
297877349Sgshapiro{
297990792Sgshapiro	int i;
298090792Sgshapiro	char *reason;
298177349Sgshapiro
298290792Sgshapiro	sm_allsignals(true);
298390792Sgshapiro
298490792Sgshapiro	reason = ShutdownRequest;
298590792Sgshapiro	ShutdownRequest = NULL;
298690792Sgshapiro	PendingSignal = 0;
298790792Sgshapiro
2988132943Sgshapiro	if (LogLevel > 9)
2989132943Sgshapiro		sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s",
299090792Sgshapiro			  reason == NULL ? "implicit call" : reason);
299190792Sgshapiro
299290792Sgshapiro	FileName = NULL;
299390792Sgshapiro	closecontrolsocket(true);
299490792Sgshapiro#if XLA
299590792Sgshapiro	xla_all_end();
299690792Sgshapiro#endif /* XLA */
299790792Sgshapiro
299890792Sgshapiro	for (i = 0; i < NDaemons; i++)
299990792Sgshapiro	{
300090792Sgshapiro		if (Daemons[i].d_socket >= 0)
300190792Sgshapiro		{
300290792Sgshapiro			(void) close(Daemons[i].d_socket);
300390792Sgshapiro			Daemons[i].d_socket = -1;
300490792Sgshapiro
300590792Sgshapiro#if _FFR_DAEMON_NETUNIX
300690792Sgshapiro# if NETUNIX
300790792Sgshapiro			/* Remove named sockets */
300890792Sgshapiro			if (Daemons[i].d_addr.sa.sa_family == AF_UNIX)
300990792Sgshapiro			{
301090792Sgshapiro				int rval;
301190792Sgshapiro				long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT;
301290792Sgshapiro
301390792Sgshapiro				/* if not safe, don't use it */
301490792Sgshapiro				rval = safefile(Daemons[i].d_addr.sunix.sun_path,
301590792Sgshapiro						RunAsUid, RunAsGid,
301690792Sgshapiro						RunAsUserName, sff,
301790792Sgshapiro						S_IRUSR|S_IWUSR, NULL);
301890792Sgshapiro				if (rval == 0 &&
301990792Sgshapiro				    unlink(Daemons[i].d_addr.sunix.sun_path) < 0)
302090792Sgshapiro				{
302190792Sgshapiro					sm_syslog(LOG_WARNING, NOQID,
302290792Sgshapiro						  "Could not remove daemon %s socket: %s: %s",
302390792Sgshapiro						  Daemons[i].d_name,
302490792Sgshapiro						  Daemons[i].d_addr.sunix.sun_path,
302590792Sgshapiro						  sm_errstring(errno));
302690792Sgshapiro				}
302790792Sgshapiro			}
302890792Sgshapiro# endif /* NETUNIX */
302990792Sgshapiro#endif	/* _FFR_DAEMON_NETUNIX */
303090792Sgshapiro		}
303190792Sgshapiro	}
303290792Sgshapiro
303390792Sgshapiro	finis(false, true, EX_OK);
303477349Sgshapiro}
303590792Sgshapiro/*
303677349Sgshapiro**  RESTART_DAEMON -- Performs a clean restart of the daemon
303777349Sgshapiro**
303877349Sgshapiro**	Parameters:
303977349Sgshapiro**		none.
304077349Sgshapiro**
304177349Sgshapiro**	Returns:
304277349Sgshapiro**		none.
304377349Sgshapiro**
304477349Sgshapiro**	Side Effects:
304577349Sgshapiro**		restarts the daemon or exits if restart fails.
304677349Sgshapiro*/
304777349Sgshapiro
304880785Sgshapiro/* Make a non-DFL/IGN signal a noop */
304980785Sgshapiro#define SM_NOOP_SIGNAL(sig, old)				\
305080785Sgshapirodo								\
305180785Sgshapiro{								\
305290792Sgshapiro	(old) = sm_signal((sig), sm_signal_noop);		\
305380785Sgshapiro	if ((old) == SIG_IGN || (old) == SIG_DFL)		\
305490792Sgshapiro		(void) sm_signal((sig), (old));			\
305580785Sgshapiro} while (0)
305680785Sgshapiro
305790792Sgshapirovoid
305877349Sgshapirorestart_daemon()
305977349Sgshapiro{
306090792Sgshapiro	bool drop;
306177349Sgshapiro	int save_errno;
306277349Sgshapiro	char *reason;
306380785Sgshapiro	sigfunc_t ignore, oalrm, ousr1;
306477349Sgshapiro	extern int DtableSize;
306577349Sgshapiro
306680785Sgshapiro	/* clear the events to turn off SIGALRMs */
306790792Sgshapiro	sm_clear_events();
306890792Sgshapiro	sm_allsignals(true);
306977349Sgshapiro
307077349Sgshapiro	reason = RestartRequest;
307177349Sgshapiro	RestartRequest = NULL;
307277349Sgshapiro	PendingSignal = 0;
307377349Sgshapiro
307477349Sgshapiro	if (SaveArgv[0][0] != '/')
307577349Sgshapiro	{
307677349Sgshapiro		if (LogLevel > 3)
307777349Sgshapiro			sm_syslog(LOG_INFO, NOQID,
307877349Sgshapiro				  "could not restart: need full path");
307990792Sgshapiro		finis(false, true, EX_OSFILE);
308090792Sgshapiro		/* NOTREACHED */
308177349Sgshapiro	}
308277349Sgshapiro	if (LogLevel > 3)
308377349Sgshapiro		sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s",
308477349Sgshapiro			  SaveArgv[0],
308577349Sgshapiro			  reason == NULL ? "implicit call" : reason);
308677349Sgshapiro
308790792Sgshapiro	closecontrolsocket(true);
308898121Sgshapiro#if SM_CONF_SHM
308998121Sgshapiro	cleanup_shm(DaemonPid == getpid());
309098121Sgshapiro#endif /* SM_CONF_SHM */
309190792Sgshapiro
3092132943Sgshapiro	/* close locked pid file */
3093132943Sgshapiro	close_sendmail_pid();
3094132943Sgshapiro
309590792Sgshapiro	/*
309690792Sgshapiro	**  Want to drop to the user who started the process in all cases
309790792Sgshapiro	**  *but* when running as "smmsp" for the clientmqueue queue run
309890792Sgshapiro	**  daemon.  In that case, UseMSP will be true, RunAsUid should not
309990792Sgshapiro	**  be root, and RealUid should be either 0 or RunAsUid.
310090792Sgshapiro	*/
310190792Sgshapiro
310290792Sgshapiro	drop = !(UseMSP && RunAsUid != 0 &&
310390792Sgshapiro		 (RealUid == 0 || RealUid == RunAsUid));
310490792Sgshapiro
310590792Sgshapiro	if (drop_privileges(drop) != EX_OK)
310677349Sgshapiro	{
310777349Sgshapiro		if (LogLevel > 0)
310877349Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
310990792Sgshapiro				  "could not drop privileges: %s",
311090792Sgshapiro				  sm_errstring(errno));
311190792Sgshapiro		finis(false, true, EX_OSERR);
311290792Sgshapiro		/* NOTREACHED */
311377349Sgshapiro	}
311477349Sgshapiro
3115132943Sgshapiro	sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
311677349Sgshapiro
311780785Sgshapiro	/*
311880785Sgshapiro	**  Need to allow signals before execve() to make them "harmless".
311980785Sgshapiro	**  However, the default action can be "terminate", so it isn't
312080785Sgshapiro	**  really harmless.  Setting signals to IGN will cause them to be
312180785Sgshapiro	**  ignored in the new process to, so that isn't a good alternative.
312280785Sgshapiro	*/
312380785Sgshapiro
312480785Sgshapiro	SM_NOOP_SIGNAL(SIGALRM, oalrm);
312580785Sgshapiro	SM_NOOP_SIGNAL(SIGCHLD, ignore);
312680785Sgshapiro	SM_NOOP_SIGNAL(SIGHUP, ignore);
312780785Sgshapiro	SM_NOOP_SIGNAL(SIGINT, ignore);
312880785Sgshapiro	SM_NOOP_SIGNAL(SIGPIPE, ignore);
312980785Sgshapiro	SM_NOOP_SIGNAL(SIGTERM, ignore);
313080785Sgshapiro#ifdef SIGUSR1
313180785Sgshapiro	SM_NOOP_SIGNAL(SIGUSR1, ousr1);
313280785Sgshapiro#endif /* SIGUSR1 */
313394334Sgshapiro
313494334Sgshapiro	/* Turn back on signals */
313590792Sgshapiro	sm_allsignals(false);
313677349Sgshapiro
313777349Sgshapiro	(void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
313877349Sgshapiro	save_errno = errno;
313977349Sgshapiro
314080785Sgshapiro	/* block signals again and restore needed signals */
314190792Sgshapiro	sm_allsignals(true);
314280785Sgshapiro
314380785Sgshapiro	/* For finis() events */
314490792Sgshapiro	(void) sm_signal(SIGALRM, oalrm);
314580785Sgshapiro
314680785Sgshapiro#ifdef SIGUSR1
314780785Sgshapiro	/* For debugging finis() */
314890792Sgshapiro	(void) sm_signal(SIGUSR1, ousr1);
314980785Sgshapiro#endif /* SIGUSR1 */
315077349Sgshapiro
315177349Sgshapiro	errno = save_errno;
315277349Sgshapiro	if (LogLevel > 0)
315390792Sgshapiro		sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s",
315490792Sgshapiro			  SaveArgv[0], sm_errstring(errno));
315590792Sgshapiro	finis(false, true, EX_OSFILE);
315690792Sgshapiro	/* NOTREACHED */
315777349Sgshapiro}
315890792Sgshapiro/*
315938032Speter**  MYHOSTNAME -- return the name of this host.
316038032Speter**
316138032Speter**	Parameters:
316238032Speter**		hostbuf -- a place to return the name of this host.
316338032Speter**		size -- the size of hostbuf.
316438032Speter**
316538032Speter**	Returns:
316638032Speter**		A list of aliases for this host.
316738032Speter**
316838032Speter**	Side Effects:
316938032Speter**		Adds numeric codes to $=w.
317038032Speter*/
317138032Speter
317238032Speterstruct hostent *
317338032Spetermyhostname(hostbuf, size)
317438032Speter	char hostbuf[];
317538032Speter	int size;
317638032Speter{
317738032Speter	register struct hostent *hp;
317838032Speter
317973188Sgshapiro	if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0')
318090792Sgshapiro		(void) sm_strlcpy(hostbuf, "localhost", size);
318164562Sgshapiro	hp = sm_gethostbyname(hostbuf, InetMode);
318290792Sgshapiro#if NETINET && NETINET6
318380785Sgshapiro	if (hp == NULL && InetMode == AF_INET6)
318480785Sgshapiro	{
318580785Sgshapiro		/*
318680785Sgshapiro		**  It's possible that this IPv6 enabled machine doesn't
318780785Sgshapiro		**  actually have any IPv6 interfaces and, therefore, no
318880785Sgshapiro		**  IPv6 addresses.  Fall back to AF_INET.
318980785Sgshapiro		*/
319080785Sgshapiro
319180785Sgshapiro		hp = sm_gethostbyname(hostbuf, AF_INET);
319280785Sgshapiro	}
319390792Sgshapiro#endif /* NETINET && NETINET6 */
319438032Speter	if (hp == NULL)
319538032Speter		return NULL;
319638032Speter	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
319764562Sgshapiro		(void) cleanstrcpy(hostbuf, hp->h_name, size);
319864562Sgshapiro
319990792Sgshapiro#if NETINFO
320064562Sgshapiro	if (strchr(hostbuf, '.') == NULL)
320138032Speter	{
320264562Sgshapiro		char *domainname;
320364562Sgshapiro
320464562Sgshapiro		domainname = ni_propval("/locations", NULL, "resolver",
320564562Sgshapiro					"domain", '\0');
320664562Sgshapiro		if (domainname != NULL &&
320764562Sgshapiro		    strlen(domainname) + strlen(hostbuf) + 1 < size)
320890792Sgshapiro			(void) sm_strlcat2(hostbuf, ".", domainname, size);
320938032Speter	}
321090792Sgshapiro#endif /* NETINFO */
321138032Speter
321238032Speter	/*
321338032Speter	**  If there is still no dot in the name, try looking for a
321438032Speter	**  dotted alias.
321538032Speter	*/
321638032Speter
321738032Speter	if (strchr(hostbuf, '.') == NULL)
321838032Speter	{
321938032Speter		char **ha;
322038032Speter
322164562Sgshapiro		for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
322238032Speter		{
322338032Speter			if (strchr(*ha, '.') != NULL)
322438032Speter			{
322564562Sgshapiro				(void) cleanstrcpy(hostbuf, *ha, size - 1);
322638032Speter				hostbuf[size - 1] = '\0';
322738032Speter				break;
322838032Speter			}
322938032Speter		}
323038032Speter	}
323138032Speter
323238032Speter	/*
323338032Speter	**  If _still_ no dot, wait for a while and try again -- it is
323438032Speter	**  possible that some service is starting up.  This can result
323538032Speter	**  in excessive delays if the system is badly configured, but
323638032Speter	**  there really isn't a way around that, particularly given that
323738032Speter	**  the config file hasn't been read at this point.
323838032Speter	**  All in all, a bit of a mess.
323938032Speter	*/
324038032Speter
324138032Speter	if (strchr(hostbuf, '.') == NULL &&
324290792Sgshapiro	    !getcanonname(hostbuf, size, true, NULL))
324338032Speter	{
324438032Speter		sm_syslog(LOG_CRIT, NOQID,
324564562Sgshapiro			  "My unqualified host name (%s) unknown; sleeping for retry",
324664562Sgshapiro			  hostbuf);
324738032Speter		message("My unqualified host name (%s) unknown; sleeping for retry",
324838032Speter			hostbuf);
324964562Sgshapiro		(void) sleep(60);
325090792Sgshapiro		if (!getcanonname(hostbuf, size, true, NULL))
325138032Speter		{
325238032Speter			sm_syslog(LOG_ALERT, NOQID,
325364562Sgshapiro				  "unable to qualify my own domain name (%s) -- using short name",
325464562Sgshapiro				  hostbuf);
325538032Speter			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
325638032Speter				hostbuf);
325738032Speter		}
325838032Speter	}
325964562Sgshapiro	return hp;
326038032Speter}
326190792Sgshapiro/*
326238032Speter**  ADDRCMP -- compare two host addresses
326338032Speter**
326438032Speter**	Parameters:
326538032Speter**		hp -- hostent structure for the first address
326638032Speter**		ha -- actual first address
326738032Speter**		sa -- second address
326838032Speter**
326938032Speter**	Returns:
327038032Speter**		0 -- if ha and sa match
327138032Speter**		else -- they don't match
327238032Speter*/
327338032Speter
327464562Sgshapirostatic int
327538032Speteraddrcmp(hp, ha, sa)
327638032Speter	struct hostent *hp;
327738032Speter	char *ha;
327838032Speter	SOCKADDR *sa;
327938032Speter{
328090792Sgshapiro#if NETINET6
328190792Sgshapiro	unsigned char *a;
328290792Sgshapiro#endif /* NETINET6 */
328364562Sgshapiro
328438032Speter	switch (sa->sa.sa_family)
328538032Speter	{
328690792Sgshapiro#if NETINET
328738032Speter	  case AF_INET:
328838032Speter		if (hp->h_addrtype == AF_INET)
328964562Sgshapiro			return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
329038032Speter		break;
329190792Sgshapiro#endif /* NETINET */
329238032Speter
329390792Sgshapiro#if NETINET6
329464562Sgshapiro	  case AF_INET6:
329590792Sgshapiro		a = (unsigned char *) &sa->sin6.sin6_addr;
329664562Sgshapiro
329764562Sgshapiro		/* Straight binary comparison */
329864562Sgshapiro		if (hp->h_addrtype == AF_INET6)
329964562Sgshapiro			return memcmp(ha, a, IN6ADDRSZ);
330064562Sgshapiro
330164562Sgshapiro		/* If IPv4-mapped IPv6 address, compare the IPv4 section */
330264562Sgshapiro		if (hp->h_addrtype == AF_INET &&
330364562Sgshapiro		    IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
330464562Sgshapiro			return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
330564562Sgshapiro		break;
330690792Sgshapiro#endif /* NETINET6 */
330738032Speter	}
330838032Speter	return -1;
330938032Speter}
331090792Sgshapiro/*
331164562Sgshapiro**  GETAUTHINFO -- get the real host name associated with a file descriptor
331238032Speter**
331338032Speter**	Uses RFC1413 protocol to try to get info from the other end.
331438032Speter**
331538032Speter**	Parameters:
331638032Speter**		fd -- the descriptor
331790792Sgshapiro**		may_be_forged -- an outage that is set to true if the
331838032Speter**			forward lookup of RealHostName does not match
331990792Sgshapiro**			RealHostAddr; set to false if they do match.
332038032Speter**
332138032Speter**	Returns:
332238032Speter**		The user@host information associated with this descriptor.
332338032Speter*/
332438032Speter
332538032Speterstatic jmp_buf	CtxAuthTimeout;
332638032Speter
332738032Speterstatic void
3328141858Sgshapiroauthtimeout(ignore)
3329141858Sgshapiro	int ignore;
333038032Speter{
333177349Sgshapiro	/*
333277349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
333377349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
333477349Sgshapiro	**	DOING.
333577349Sgshapiro	*/
333677349Sgshapiro
333777349Sgshapiro	errno = ETIMEDOUT;
333838032Speter	longjmp(CtxAuthTimeout, 1);
333938032Speter}
334038032Speter
334138032Speterchar *
334238032Spetergetauthinfo(fd, may_be_forged)
334338032Speter	int fd;
334438032Speter	bool *may_be_forged;
334538032Speter{
334690792Sgshapiro	unsigned short SM_NONVOLATILE port = 0;
334738032Speter	SOCKADDR_LEN_T falen;
334838032Speter	register char *volatile p = NULL;
334938032Speter	SOCKADDR la;
335038032Speter	SOCKADDR_LEN_T lalen;
335190792Sgshapiro#ifndef NO_GETSERVBYNAME
335238032Speter	register struct servent *sp;
335390792Sgshapiro# if NETINET
335490792Sgshapiro	static unsigned short port4 = 0;
335590792Sgshapiro# endif /* NETINET */
335690792Sgshapiro# if NETINET6
335790792Sgshapiro	static unsigned short port6 = 0;
335890792Sgshapiro# endif /* NETINET6 */
335990792Sgshapiro#endif /* ! NO_GETSERVBYNAME */
336038032Speter	volatile int s;
336138032Speter	int i = 0;
336290792Sgshapiro	size_t len;
336390792Sgshapiro	SM_EVENT *ev;
336438032Speter	int nleft;
336538032Speter	struct hostent *hp;
336638032Speter	char *ostype = NULL;
336738032Speter	char **ha;
336838032Speter	char ibuf[MAXNAME + 1];
3369110560Sgshapiro	static char hbuf[MAXNAME + MAXAUTHINFO + 11];
337038032Speter
337190792Sgshapiro	*may_be_forged = false;
337238032Speter	falen = sizeof RealHostAddr;
337338032Speter	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
337438032Speter	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
337538032Speter	{
337664562Sgshapiro		if (i < 0)
337764562Sgshapiro		{
337864562Sgshapiro			/*
337964562Sgshapiro			**  ENOTSOCK is OK: bail on anything else, but reset
338064562Sgshapiro			**  errno in this case, so a mis-report doesn't
338164562Sgshapiro			**  happen later.
338264562Sgshapiro			*/
338390792Sgshapiro
338464562Sgshapiro			if (errno != ENOTSOCK)
338564562Sgshapiro				return NULL;
338664562Sgshapiro			errno = 0;
338764562Sgshapiro		}
338890792Sgshapiro		(void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName,
338990792Sgshapiro				   "@localhost");
339038032Speter		if (tTd(9, 1))
339190792Sgshapiro			sm_dprintf("getauthinfo: %s\n", hbuf);
339238032Speter		return hbuf;
339338032Speter	}
339438032Speter
339538032Speter	if (RealHostName == NULL)
339638032Speter	{
339738032Speter		/* translate that to a host name */
339838032Speter		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
339938032Speter		if (strlen(RealHostName) > MAXNAME)
340090792Sgshapiro			RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */
340138032Speter	}
340238032Speter
340338032Speter	/* cross check RealHostName with forward DNS lookup */
340490792Sgshapiro	if (anynet_ntoa(&RealHostAddr)[0] != '[' &&
340590792Sgshapiro	    RealHostName[0] != '[')
340638032Speter	{
340780785Sgshapiro		int family;
340880785Sgshapiro
340980785Sgshapiro		family = RealHostAddr.sa.sa_family;
341090792Sgshapiro#if NETINET6 && NEEDSGETIPNODE
341180785Sgshapiro		/*
341280785Sgshapiro		**  If RealHostAddr is an IPv6 connection with an
341380785Sgshapiro		**  IPv4-mapped address, we need RealHostName's IPv4
341480785Sgshapiro		**  address(es) for addrcmp() to compare against
341580785Sgshapiro		**  RealHostAddr.
341680785Sgshapiro		**
341780785Sgshapiro		**  Actually, we only need to do this for systems
341880785Sgshapiro		**  which NEEDSGETIPNODE since the real getipnodebyname()
341980785Sgshapiro		**  already does V4MAPPED address via the AI_V4MAPPEDCFG
342080785Sgshapiro		**  flag.  A better fix to this problem is to add this
342180785Sgshapiro		**  functionality to our stub getipnodebyname().
342280785Sgshapiro		*/
342380785Sgshapiro
342480785Sgshapiro		if (family == AF_INET6 &&
342580785Sgshapiro		    IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr))
342680785Sgshapiro			family = AF_INET;
342790792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */
342880785Sgshapiro
342938032Speter		/* try to match the reverse against the forward lookup */
343080785Sgshapiro		hp = sm_gethostbyname(RealHostName, family);
343138032Speter		if (hp == NULL)
3432120256Sgshapiro		{
3433132943Sgshapiro			/* XXX: Could be a temporary error on forward lookup */
343490792Sgshapiro			*may_be_forged = true;
3435120256Sgshapiro		}
343638032Speter		else
343738032Speter		{
343838032Speter			for (ha = hp->h_addr_list; *ha != NULL; ha++)
343990792Sgshapiro			{
344038032Speter				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
344138032Speter					break;
344290792Sgshapiro			}
344338032Speter			*may_be_forged = *ha == NULL;
344490792Sgshapiro#if NETINET6
344571345Sgshapiro			freehostent(hp);
344671345Sgshapiro			hp = NULL;
344790792Sgshapiro#endif /* NETINET6 */
344838032Speter		}
344938032Speter	}
345038032Speter
345138032Speter	if (TimeOuts.to_ident == 0)
345238032Speter		goto noident;
345338032Speter
345438032Speter	lalen = sizeof la;
345564562Sgshapiro	switch (RealHostAddr.sa.sa_family)
345638032Speter	{
345790792Sgshapiro#if NETINET
345864562Sgshapiro	  case AF_INET:
345964562Sgshapiro		if (getsockname(fd, &la.sa, &lalen) < 0 ||
346064562Sgshapiro		    lalen <= 0 ||
346164562Sgshapiro		    la.sa.sa_family != AF_INET)
346264562Sgshapiro		{
346364562Sgshapiro			/* no ident info */
346464562Sgshapiro			goto noident;
346564562Sgshapiro		}
346664562Sgshapiro		port = RealHostAddr.sin.sin_port;
346738032Speter
346864562Sgshapiro		/* create ident query */
346990792Sgshapiro		(void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
347064562Sgshapiro				ntohs(RealHostAddr.sin.sin_port),
347164562Sgshapiro				ntohs(la.sin.sin_port));
347238032Speter
347364562Sgshapiro		/* create local address */
347464562Sgshapiro		la.sin.sin_port = 0;
347538032Speter
347664562Sgshapiro		/* create foreign address */
347790792Sgshapiro# ifdef NO_GETSERVBYNAME
347838032Speter		RealHostAddr.sin.sin_port = htons(113);
347990792Sgshapiro# else /* NO_GETSERVBYNAME */
348090792Sgshapiro
348190792Sgshapiro		/*
348290792Sgshapiro		**  getservbyname() consumes about 5% of the time
348390792Sgshapiro		**  when receiving a small message (almost all of the time
348490792Sgshapiro		**  spent in this routine).
348590792Sgshapiro		**  Hence we store the port in a static variable
348690792Sgshapiro		**  to save this time.
348790792Sgshapiro		**  The portnumber shouldn't change very often...
348890792Sgshapiro		**  This code makes the assumption that the port number
348990792Sgshapiro		**  is not 0.
349090792Sgshapiro		*/
349190792Sgshapiro
349290792Sgshapiro		if (port4 == 0)
349390792Sgshapiro		{
349490792Sgshapiro			sp = getservbyname("auth", "tcp");
349590792Sgshapiro			if (sp != NULL)
349690792Sgshapiro				port4 = sp->s_port;
349790792Sgshapiro			else
349890792Sgshapiro				port4 = htons(113);
349990792Sgshapiro		}
350090792Sgshapiro		RealHostAddr.sin.sin_port = port4;
350164562Sgshapiro		break;
350290792Sgshapiro# endif /* NO_GETSERVBYNAME */
350390792Sgshapiro#endif /* NETINET */
350438032Speter
350590792Sgshapiro#if NETINET6
350664562Sgshapiro	  case AF_INET6:
350764562Sgshapiro		if (getsockname(fd, &la.sa, &lalen) < 0 ||
350864562Sgshapiro		    lalen <= 0 ||
350964562Sgshapiro		    la.sa.sa_family != AF_INET6)
351064562Sgshapiro		{
351164562Sgshapiro			/* no ident info */
351264562Sgshapiro			goto noident;
351364562Sgshapiro		}
351464562Sgshapiro		port = RealHostAddr.sin6.sin6_port;
351564562Sgshapiro
351664562Sgshapiro		/* create ident query */
351790792Sgshapiro		(void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
351864562Sgshapiro				ntohs(RealHostAddr.sin6.sin6_port),
351964562Sgshapiro				ntohs(la.sin6.sin6_port));
352064562Sgshapiro
352164562Sgshapiro		/* create local address */
352264562Sgshapiro		la.sin6.sin6_port = 0;
352364562Sgshapiro
352464562Sgshapiro		/* create foreign address */
352590792Sgshapiro# ifdef NO_GETSERVBYNAME
352664562Sgshapiro		RealHostAddr.sin6.sin6_port = htons(113);
352790792Sgshapiro# else /* NO_GETSERVBYNAME */
352890792Sgshapiro		if (port6 == 0)
352990792Sgshapiro		{
353090792Sgshapiro			sp = getservbyname("auth", "tcp");
353190792Sgshapiro			if (sp != NULL)
353290792Sgshapiro				port6 = sp->s_port;
353390792Sgshapiro			else
353490792Sgshapiro				port6 = htons(113);
353590792Sgshapiro		}
353690792Sgshapiro		RealHostAddr.sin6.sin6_port = port6;
353764562Sgshapiro		break;
353890792Sgshapiro# endif /* NO_GETSERVBYNAME */
353990792Sgshapiro#endif /* NETINET6 */
354064562Sgshapiro	  default:
354164562Sgshapiro		/* no ident info */
354264562Sgshapiro		goto noident;
354364562Sgshapiro	}
354464562Sgshapiro
354538032Speter	s = -1;
354638032Speter	if (setjmp(CtxAuthTimeout) != 0)
354738032Speter	{
354838032Speter		if (s >= 0)
354938032Speter			(void) close(s);
355038032Speter		goto noident;
355138032Speter	}
355238032Speter
355338032Speter	/* put a timeout around the whole thing */
355490792Sgshapiro	ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0);
355538032Speter
355638032Speter	/* connect to foreign IDENT server using same address as SMTP socket */
355764562Sgshapiro	s = socket(la.sa.sa_family, SOCK_STREAM, 0);
355838032Speter	if (s < 0)
355938032Speter	{
356090792Sgshapiro		sm_clrevent(ev);
356138032Speter		goto noident;
356238032Speter	}
356364562Sgshapiro	if (bind(s, &la.sa, lalen) < 0 ||
356464562Sgshapiro	    connect(s, &RealHostAddr.sa, lalen) < 0)
356538032Speter		goto closeident;
356638032Speter
356738032Speter	if (tTd(9, 10))
356890792Sgshapiro		sm_dprintf("getauthinfo: sent %s", ibuf);
356938032Speter
357038032Speter	/* send query */
357138032Speter	if (write(s, ibuf, strlen(ibuf)) < 0)
357238032Speter		goto closeident;
357338032Speter
357438032Speter	/* get result */
357538032Speter	p = &ibuf[0];
357638032Speter	nleft = sizeof ibuf - 1;
357738032Speter	while ((i = read(s, p, nleft)) > 0)
357838032Speter	{
3579125820Sgshapiro		char *s;
3580125820Sgshapiro
358138032Speter		p += i;
358238032Speter		nleft -= i;
358338032Speter		*p = '\0';
3584125820Sgshapiro		if ((s = strchr(ibuf, '\n')) != NULL)
3585125820Sgshapiro		{
3586125820Sgshapiro			if (p > s + 1)
3587125820Sgshapiro			{
3588125820Sgshapiro				p = s + 1;
3589125820Sgshapiro				*p = '\0';
3590125820Sgshapiro			}
359138032Speter			break;
3592125820Sgshapiro		}
3593125820Sgshapiro		if (nleft <= 0)
3594125820Sgshapiro			break;
359538032Speter	}
359638032Speter	(void) close(s);
359790792Sgshapiro	sm_clrevent(ev);
359838032Speter	if (i < 0 || p == &ibuf[0])
359938032Speter		goto noident;
360038032Speter
3601111823Sgshapiro	if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r')
360238032Speter		p--;
360338032Speter	*++p = '\0';
360438032Speter
360538032Speter	if (tTd(9, 3))
360690792Sgshapiro		sm_dprintf("getauthinfo:  got %s\n", ibuf);
360738032Speter
360838032Speter	/* parse result */
360938032Speter	p = strchr(ibuf, ':');
361038032Speter	if (p == NULL)
361138032Speter	{
361238032Speter		/* malformed response */
361338032Speter		goto noident;
361438032Speter	}
361538032Speter	while (isascii(*++p) && isspace(*p))
361638032Speter		continue;
361790792Sgshapiro	if (sm_strncasecmp(p, "userid", 6) != 0)
361838032Speter	{
361938032Speter		/* presumably an error string */
362038032Speter		goto noident;
362138032Speter	}
362238032Speter	p += 6;
362338032Speter	while (isascii(*p) && isspace(*p))
362438032Speter		p++;
362538032Speter	if (*p++ != ':')
362638032Speter	{
362738032Speter		/* either useridxx or malformed response */
362838032Speter		goto noident;
362938032Speter	}
363038032Speter
363138032Speter	/* p now points to the OSTYPE field */
363238032Speter	while (isascii(*p) && isspace(*p))
363338032Speter		p++;
363438032Speter	ostype = p;
363538032Speter	p = strchr(p, ':');
363638032Speter	if (p == NULL)
363738032Speter	{
363838032Speter		/* malformed response */
363938032Speter		goto noident;
364038032Speter	}
364138032Speter	else
364238032Speter	{
364338032Speter		char *charset;
364438032Speter
364538032Speter		*p = '\0';
364638032Speter		charset = strchr(ostype, ',');
364738032Speter		if (charset != NULL)
364838032Speter			*charset = '\0';
364938032Speter	}
365038032Speter
365138032Speter	/* 1413 says don't do this -- but it's broken otherwise */
365238032Speter	while (isascii(*++p) && isspace(*p))
365338032Speter		continue;
365438032Speter
365538032Speter	/* p now points to the authenticated name -- copy carefully */
365690792Sgshapiro	if (sm_strncasecmp(ostype, "other", 5) == 0 &&
365738032Speter	    (ostype[5] == ' ' || ostype[5] == '\0'))
365838032Speter	{
365990792Sgshapiro		(void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf);
3660110560Sgshapiro		cleanstrcpy(&hbuf[6], p, MAXAUTHINFO);
366138032Speter	}
366238032Speter	else
3663110560Sgshapiro		cleanstrcpy(hbuf, p, MAXAUTHINFO);
366490792Sgshapiro	len = strlen(hbuf);
366590792Sgshapiro	(void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@",
366690792Sgshapiro			   RealHostName == NULL ? "localhost" : RealHostName);
366738032Speter	goto postident;
366838032Speter
366938032Spetercloseident:
367038032Speter	(void) close(s);
367190792Sgshapiro	sm_clrevent(ev);
367238032Speter
367338032Speternoident:
367464562Sgshapiro	/* put back the original incoming port */
367564562Sgshapiro	switch (RealHostAddr.sa.sa_family)
367664562Sgshapiro	{
367790792Sgshapiro#if NETINET
367864562Sgshapiro	  case AF_INET:
367964562Sgshapiro		if (port > 0)
368064562Sgshapiro			RealHostAddr.sin.sin_port = port;
368164562Sgshapiro		break;
368290792Sgshapiro#endif /* NETINET */
368364562Sgshapiro
368490792Sgshapiro#if NETINET6
368564562Sgshapiro	  case AF_INET6:
368664562Sgshapiro		if (port > 0)
368764562Sgshapiro			RealHostAddr.sin6.sin6_port = port;
368864562Sgshapiro		break;
368990792Sgshapiro#endif /* NETINET6 */
369064562Sgshapiro	}
369164562Sgshapiro
369238032Speter	if (RealHostName == NULL)
369338032Speter	{
369438032Speter		if (tTd(9, 1))
369590792Sgshapiro			sm_dprintf("getauthinfo: NULL\n");
369638032Speter		return NULL;
369738032Speter	}
369890792Sgshapiro	(void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf);
369938032Speter
370038032Speterpostident:
370190792Sgshapiro#if IP_SRCROUTE
370290792Sgshapiro# ifndef GET_IPOPT_DST
370390792Sgshapiro#  define GET_IPOPT_DST(dst)	(dst)
370490792Sgshapiro# endif /* ! GET_IPOPT_DST */
370538032Speter	/*
370638032Speter	**  Extract IP source routing information.
370738032Speter	**
370838032Speter	**	Format of output for a connection from site a through b
370938032Speter	**	through c to d:
371038032Speter	**		loose:      @site-c@site-b:site-a
371138032Speter	**		strict:	   !@site-c@site-b:site-a
371238032Speter	**
371338032Speter	**	o - pointer within ipopt_list structure.
371438032Speter	**	q - pointer within ls/ss rr route data
371538032Speter	**	p - pointer to hbuf
371638032Speter	*/
371738032Speter
371838032Speter	if (RealHostAddr.sa.sa_family == AF_INET)
371938032Speter	{
372038032Speter		SOCKOPT_LEN_T ipoptlen;
372138032Speter		int j;
372290792Sgshapiro		unsigned char *q;
372390792Sgshapiro		unsigned char *o;
372438032Speter		int l;
372564562Sgshapiro		struct IPOPTION ipopt;
372638032Speter
372738032Speter		ipoptlen = sizeof ipopt;
372838032Speter		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
372938032Speter			       (char *) &ipopt, &ipoptlen) < 0)
373038032Speter			goto noipsr;
373138032Speter		if (ipoptlen == 0)
373238032Speter			goto noipsr;
373390792Sgshapiro		o = (unsigned char *) ipopt.IP_LIST;
373490792Sgshapiro		while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen)
373538032Speter		{
373638032Speter			switch (*o)
373738032Speter			{
373864562Sgshapiro			  case IPOPT_EOL:
373938032Speter				o = NULL;
374038032Speter				break;
374138032Speter
374238032Speter			  case IPOPT_NOP:
374338032Speter				o++;
374438032Speter				break;
374538032Speter
374638032Speter			  case IPOPT_SSRR:
374738032Speter			  case IPOPT_LSRR:
374838032Speter				/*
374938032Speter				**  Source routing.
375038032Speter				**	o[0] is the option type (loose/strict).
375138032Speter				**	o[1] is the length of this option,
375238032Speter				**		including option type and
375338032Speter				**		length.
375438032Speter				**	o[2] is the pointer into the route
375538032Speter				**		data.
375638032Speter				**	o[3] begins the route data.
375738032Speter				*/
375838032Speter
375938032Speter				p = &hbuf[strlen(hbuf)];
376038032Speter				l = sizeof hbuf - (hbuf - p) - 6;
376190792Sgshapiro				(void) sm_snprintf(p, SPACELEFT(hbuf, p),
376290792Sgshapiro					" [%s@%.*s",
376390792Sgshapiro					*o == IPOPT_SSRR ? "!" : "",
376490792Sgshapiro					l > 240 ? 120 : l / 2,
376590792Sgshapiro					inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
376638032Speter				i = strlen(p);
376738032Speter				p += i;
376838032Speter				l -= strlen(p);
376938032Speter
377038032Speter				j = o[1] / sizeof(struct in_addr) - 1;
377138032Speter
377238032Speter				/* q skips length and router pointer to data */
377338032Speter				q = &o[3];
377438032Speter				for ( ; j >= 0; j--)
377538032Speter				{
377664562Sgshapiro					struct in_addr addr;
377764562Sgshapiro
377838032Speter					memcpy(&addr, q, sizeof(addr));
377990792Sgshapiro					(void) sm_snprintf(p,
378090792Sgshapiro						SPACELEFT(hbuf, p),
378190792Sgshapiro						"%c%.*s",
378290792Sgshapiro						j != 0 ? '@' : ':',
378390792Sgshapiro						l > 240 ? 120 :
378490792Sgshapiro							j == 0 ? l : l / 2,
378590792Sgshapiro						inet_ntoa(addr));
378638032Speter					i = strlen(p);
378738032Speter					p += i;
378838032Speter					l -= i + 1;
378964562Sgshapiro					q += sizeof(struct in_addr);
379038032Speter				}
379138032Speter				o += o[1];
379238032Speter				break;
379338032Speter
379438032Speter			  default:
379538032Speter				/* Skip over option */
379638032Speter				o += o[1];
379738032Speter				break;
379838032Speter			}
379938032Speter		}
380090792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(hbuf, p), "]");
380138032Speter		goto postipsr;
380238032Speter	}
380338032Speter
380438032Speternoipsr:
380590792Sgshapiro#endif /* IP_SRCROUTE */
380638032Speter	if (RealHostName != NULL && RealHostName[0] != '[')
380738032Speter	{
380838032Speter		p = &hbuf[strlen(hbuf)];
380990792Sgshapiro		(void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
381090792Sgshapiro				   anynet_ntoa(&RealHostAddr));
381138032Speter	}
381238032Speter	if (*may_be_forged)
381338032Speter	{
381438032Speter		p = &hbuf[strlen(hbuf)];
381590792Sgshapiro		(void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p));
381690792Sgshapiro		macdefine(&BlankEnvelope.e_macro, A_PERM,
381790792Sgshapiro			  macid("{client_resolve}"), "FORGED");
381838032Speter	}
381938032Speter
382090792Sgshapiro#if IP_SRCROUTE
382138032Speterpostipsr:
382290792Sgshapiro#endif /* IP_SRCROUTE */
382364562Sgshapiro
382464562Sgshapiro	/* put back the original incoming port */
382564562Sgshapiro	switch (RealHostAddr.sa.sa_family)
382664562Sgshapiro	{
382790792Sgshapiro#if NETINET
382864562Sgshapiro	  case AF_INET:
382964562Sgshapiro		if (port > 0)
383064562Sgshapiro			RealHostAddr.sin.sin_port = port;
383164562Sgshapiro		break;
383290792Sgshapiro#endif /* NETINET */
383364562Sgshapiro
383490792Sgshapiro#if NETINET6
383564562Sgshapiro	  case AF_INET6:
383664562Sgshapiro		if (port > 0)
383764562Sgshapiro			RealHostAddr.sin6.sin6_port = port;
383864562Sgshapiro		break;
383990792Sgshapiro#endif /* NETINET6 */
384064562Sgshapiro	}
384164562Sgshapiro
384290792Sgshapiro	if (tTd(9, 1))
384390792Sgshapiro		sm_dprintf("getauthinfo: %s\n", hbuf);
384438032Speter	return hbuf;
384538032Speter}
384690792Sgshapiro/*
384738032Speter**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
384838032Speter**
384938032Speter**	Parameters:
385038032Speter**		map -- a pointer to this map.
385138032Speter**		name -- the (presumably unqualified) hostname.
385238032Speter**		av -- unused -- for compatibility with other mapping
385338032Speter**			functions.
385438032Speter**		statp -- an exit status (out parameter) -- set to
385538032Speter**			EX_TEMPFAIL if the name server is unavailable.
385638032Speter**
385738032Speter**	Returns:
385838032Speter**		The mapping, if found.
385938032Speter**		NULL if no mapping found.
386038032Speter**
386138032Speter**	Side Effects:
386238032Speter**		Looks up the host specified in hbuf.  If it is not
386338032Speter**		the canonical name for that host, return the canonical
386438032Speter**		name (unless MF_MATCHONLY is set, which will cause the
386538032Speter**		status only to be returned).
386638032Speter*/
386738032Speter
386838032Speterchar *
386938032Speterhost_map_lookup(map, name, av, statp)
387038032Speter	MAP *map;
387138032Speter	char *name;
387238032Speter	char **av;
387338032Speter	int *statp;
387438032Speter{
387538032Speter	register struct hostent *hp;
387690792Sgshapiro#if NETINET
387738032Speter	struct in_addr in_addr;
387890792Sgshapiro#endif /* NETINET */
387990792Sgshapiro#if NETINET6
388064562Sgshapiro	struct in6_addr in6_addr;
388190792Sgshapiro#endif /* NETINET6 */
388264562Sgshapiro	char *cp, *ans = NULL;
388338032Speter	register STAB *s;
388490792Sgshapiro	time_t now;
388590792Sgshapiro#if NAMED_BIND
388690792Sgshapiro	time_t SM_NONVOLATILE retrans = 0;
388790792Sgshapiro	int SM_NONVOLATILE retry = 0;
388890792Sgshapiro#endif /* NAMED_BIND */
388938032Speter	char hbuf[MAXNAME + 1];
389038032Speter
389138032Speter	/*
389238032Speter	**  See if we have already looked up this name.  If so, just
389390792Sgshapiro	**  return it (unless expired).
389438032Speter	*/
389538032Speter
389690792Sgshapiro	now = curtime();
389738032Speter	s = stab(name, ST_NAMECANON, ST_ENTER);
389890792Sgshapiro	if (bitset(NCF_VALID, s->s_namecanon.nc_flags) &&
389990792Sgshapiro	    s->s_namecanon.nc_exp >= now)
390038032Speter	{
390138032Speter		if (tTd(9, 1))
390290792Sgshapiro			sm_dprintf("host_map_lookup(%s) => CACHE %s\n",
390390792Sgshapiro				    name,
390490792Sgshapiro				    s->s_namecanon.nc_cname == NULL
390538032Speter					? "NULL"
390638032Speter					: s->s_namecanon.nc_cname);
390738032Speter		errno = s->s_namecanon.nc_errno;
390873188Sgshapiro		SM_SET_H_ERRNO(s->s_namecanon.nc_herrno);
390938032Speter		*statp = s->s_namecanon.nc_stat;
391038032Speter		if (*statp == EX_TEMPFAIL)
391138032Speter		{
391238032Speter			CurEnv->e_status = "4.4.3";
391338032Speter			message("851 %s: Name server timeout",
391438032Speter				shortenstring(name, 33));
391538032Speter		}
391638032Speter		if (*statp != EX_OK)
391738032Speter			return NULL;
391838032Speter		if (s->s_namecanon.nc_cname == NULL)
391938032Speter		{
3920132943Sgshapiro			syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d",
392164562Sgshapiro			       name,
392264562Sgshapiro			       s->s_namecanon.nc_errno,
392364562Sgshapiro			       s->s_namecanon.nc_herrno);
392438032Speter			return NULL;
392538032Speter		}
392638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
392738032Speter			cp = map_rewrite(map, name, strlen(name), NULL);
392838032Speter		else
392938032Speter			cp = map_rewrite(map,
393038032Speter					 s->s_namecanon.nc_cname,
393138032Speter					 strlen(s->s_namecanon.nc_cname),
393238032Speter					 av);
393338032Speter		return cp;
393438032Speter	}
393538032Speter
393638032Speter	/*
393738032Speter	**  If we are running without a regular network connection (usually
393838032Speter	**  dial-on-demand) and we are just queueing, we want to avoid DNS
393938032Speter	**  lookups because those could try to connect to a server.
394038032Speter	*/
394138032Speter
394264562Sgshapiro	if (CurEnv->e_sendmode == SM_DEFER &&
394364562Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
394438032Speter	{
394538032Speter		if (tTd(9, 1))
394690792Sgshapiro			sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name);
394738032Speter		*statp = EX_TEMPFAIL;
394838032Speter		return NULL;
394938032Speter	}
395038032Speter
395138032Speter	/*
395238032Speter	**  If first character is a bracket, then it is an address
395338032Speter	**  lookup.  Address is copied into a temporary buffer to
395438032Speter	**  strip the brackets and to preserve name if address is
395538032Speter	**  unknown.
395638032Speter	*/
395738032Speter
395864562Sgshapiro	if (tTd(9, 1))
395990792Sgshapiro		sm_dprintf("host_map_lookup(%s) => ", name);
396090792Sgshapiro#if NAMED_BIND
396190792Sgshapiro	if (map->map_timeout > 0)
396290792Sgshapiro	{
396390792Sgshapiro		retrans = _res.retrans;
396490792Sgshapiro		_res.retrans = map->map_timeout;
396590792Sgshapiro	}
396690792Sgshapiro	if (map->map_retry > 0)
396790792Sgshapiro	{
396890792Sgshapiro		retry = _res.retry;
396990792Sgshapiro		_res.retry = map->map_retry;
397090792Sgshapiro	}
397190792Sgshapiro#endif /* NAMED_BIND */
397290792Sgshapiro
397390792Sgshapiro	/* set default TTL */
397490792Sgshapiro	s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL;
397538032Speter	if (*name != '[')
397638032Speter	{
397790792Sgshapiro		int ttl;
397890792Sgshapiro
397990792Sgshapiro		(void) sm_strlcpy(hbuf, name, sizeof hbuf);
398090792Sgshapiro		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl))
398190792Sgshapiro		{
398264562Sgshapiro			ans = hbuf;
398390792Sgshapiro			if (ttl > 0)
398490792Sgshapiro				s->s_namecanon.nc_exp = now + SM_MIN(ttl,
398590792Sgshapiro								SM_DEFAULT_TTL);
398690792Sgshapiro		}
398764562Sgshapiro	}
398864562Sgshapiro	else
398964562Sgshapiro	{
399064562Sgshapiro		if ((cp = strchr(name, ']')) == NULL)
399171345Sgshapiro		{
399271345Sgshapiro			if (tTd(9, 1))
399390792Sgshapiro				sm_dprintf("FAILED\n");
399464562Sgshapiro			return NULL;
399571345Sgshapiro		}
399664562Sgshapiro		*cp = '\0';
399764562Sgshapiro
399864562Sgshapiro		hp = NULL;
399990792Sgshapiro#if NETINET
400064562Sgshapiro		if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
400164562Sgshapiro			hp = sm_gethostbyaddr((char *)&in_addr,
400264562Sgshapiro					      INADDRSZ, AF_INET);
400390792Sgshapiro#endif /* NETINET */
400490792Sgshapiro#if NETINET6
400564562Sgshapiro		if (hp == NULL &&
400690792Sgshapiro		    anynet_pton(AF_INET6, &name[1], &in6_addr) == 1)
400764562Sgshapiro			hp = sm_gethostbyaddr((char *)&in6_addr,
400864562Sgshapiro					      IN6ADDRSZ, AF_INET6);
400990792Sgshapiro#endif /* NETINET6 */
401064562Sgshapiro		*cp = ']';
401164562Sgshapiro
401264562Sgshapiro		if (hp != NULL)
401338032Speter		{
401464562Sgshapiro			/* found a match -- copy out */
401590792Sgshapiro			ans = denlstring((char *) hp->h_name, true, true);
401690792Sgshapiro#if NETINET6
401790792Sgshapiro			if (ans == hp->h_name)
401890792Sgshapiro			{
401990792Sgshapiro				static char n[MAXNAME + 1];
402090792Sgshapiro
402190792Sgshapiro				/* hp->h_name is about to disappear */
402290792Sgshapiro				(void) sm_strlcpy(n, ans, sizeof n);
402390792Sgshapiro				ans = n;
402490792Sgshapiro			}
402571345Sgshapiro			freehostent(hp);
402671345Sgshapiro			hp = NULL;
402790792Sgshapiro#endif /* NETINET6 */
402838032Speter		}
402964562Sgshapiro	}
403090792Sgshapiro#if NAMED_BIND
403190792Sgshapiro	if (map->map_timeout > 0)
403290792Sgshapiro		_res.retrans = retrans;
403390792Sgshapiro	if (map->map_retry > 0)
403490792Sgshapiro		_res.retry = retry;
403590792Sgshapiro#endif /* NAMED_BIND */
403638032Speter
403764562Sgshapiro	s->s_namecanon.nc_flags |= NCF_VALID;	/* will be soon */
403838032Speter
403964562Sgshapiro	/* Found an answer */
404064562Sgshapiro	if (ans != NULL)
404164562Sgshapiro	{
404264562Sgshapiro		s->s_namecanon.nc_stat = *statp = EX_OK;
404390792Sgshapiro		if (s->s_namecanon.nc_cname != NULL)
404490792Sgshapiro			sm_free(s->s_namecanon.nc_cname);
404590792Sgshapiro		s->s_namecanon.nc_cname = sm_strdup_x(ans);
404664562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
404764562Sgshapiro			cp = map_rewrite(map, name, strlen(name), NULL);
404864562Sgshapiro		else
404964562Sgshapiro			cp = map_rewrite(map, ans, strlen(ans), av);
405071345Sgshapiro		if (tTd(9, 1))
405190792Sgshapiro			sm_dprintf("FOUND %s\n", ans);
405264562Sgshapiro		return cp;
405338032Speter	}
405438032Speter
405564562Sgshapiro
405664562Sgshapiro	/* No match found */
405738032Speter	s->s_namecanon.nc_errno = errno;
405890792Sgshapiro#if NAMED_BIND
405938032Speter	s->s_namecanon.nc_herrno = h_errno;
406064562Sgshapiro	if (tTd(9, 1))
406190792Sgshapiro		sm_dprintf("FAIL (%d)\n", h_errno);
406264562Sgshapiro	switch (h_errno)
406338032Speter	{
406464562Sgshapiro	  case TRY_AGAIN:
406564562Sgshapiro		if (UseNameServer)
406664562Sgshapiro		{
406764562Sgshapiro			CurEnv->e_status = "4.4.3";
406864562Sgshapiro			message("851 %s: Name server timeout",
406964562Sgshapiro				shortenstring(name, 33));
407064562Sgshapiro		}
407164562Sgshapiro		*statp = EX_TEMPFAIL;
407264562Sgshapiro		break;
407364562Sgshapiro
407464562Sgshapiro	  case HOST_NOT_FOUND:
407564562Sgshapiro	  case NO_DATA:
407664562Sgshapiro		*statp = EX_NOHOST;
407764562Sgshapiro		break;
407864562Sgshapiro
407964562Sgshapiro	  case NO_RECOVERY:
408064562Sgshapiro		*statp = EX_SOFTWARE;
408164562Sgshapiro		break;
408264562Sgshapiro
408364562Sgshapiro	  default:
408464562Sgshapiro		*statp = EX_UNAVAILABLE;
408564562Sgshapiro		break;
408638032Speter	}
408790792Sgshapiro#else /* NAMED_BIND */
408864562Sgshapiro	if (tTd(9, 1))
408990792Sgshapiro		sm_dprintf("FAIL\n");
409064562Sgshapiro	*statp = EX_NOHOST;
409190792Sgshapiro#endif /* NAMED_BIND */
409264562Sgshapiro	s->s_namecanon.nc_stat = *statp;
409364562Sgshapiro	return NULL;
409438032Speter}
409538032Speter/*
409690792Sgshapiro**  HOST_MAP_INIT -- initialize host class structures
409738032Speter**
409838032Speter**	Parameters:
409990792Sgshapiro**		map -- a pointer to this map.
410090792Sgshapiro**		args -- argument string.
410138032Speter**
410238032Speter**	Returns:
410390792Sgshapiro**		true.
410438032Speter*/
410538032Speter
410638032Speterbool
410738032Speterhost_map_init(map, args)
410838032Speter	MAP *map;
410938032Speter	char *args;
411038032Speter{
411138032Speter	register char *p = args;
411238032Speter
411338032Speter	for (;;)
411438032Speter	{
411538032Speter		while (isascii(*p) && isspace(*p))
411638032Speter			p++;
411738032Speter		if (*p != '-')
411838032Speter			break;
411938032Speter		switch (*++p)
412038032Speter		{
412138032Speter		  case 'a':
412238032Speter			map->map_app = ++p;
412338032Speter			break;
412438032Speter
412538032Speter		  case 'T':
412638032Speter			map->map_tapp = ++p;
412738032Speter			break;
412838032Speter
412938032Speter		  case 'm':
413038032Speter			map->map_mflags |= MF_MATCHONLY;
413138032Speter			break;
413238032Speter
413338032Speter		  case 't':
413438032Speter			map->map_mflags |= MF_NODEFER;
413538032Speter			break;
413664562Sgshapiro
413764562Sgshapiro		  case 'S':	/* only for consistency */
413864562Sgshapiro			map->map_spacesub = *++p;
413964562Sgshapiro			break;
414064562Sgshapiro
414164562Sgshapiro		  case 'D':
414264562Sgshapiro			map->map_mflags |= MF_DEFER;
414364562Sgshapiro			break;
414490792Sgshapiro
414590792Sgshapiro		  case 'd':
414690792Sgshapiro			{
414790792Sgshapiro				char *h;
414890792Sgshapiro
414990792Sgshapiro				while (isascii(*++p) && isspace(*p))
415090792Sgshapiro					continue;
415190792Sgshapiro				h = strchr(p, ' ');
415290792Sgshapiro				if (h != NULL)
415390792Sgshapiro					*h = '\0';
415490792Sgshapiro				map->map_timeout = convtime(p, 's');
415590792Sgshapiro				if (h != NULL)
415690792Sgshapiro					*h = ' ';
415790792Sgshapiro			}
415890792Sgshapiro			break;
415990792Sgshapiro
416090792Sgshapiro		  case 'r':
416190792Sgshapiro			while (isascii(*++p) && isspace(*p))
416290792Sgshapiro				continue;
416390792Sgshapiro			map->map_retry = atoi(p);
416490792Sgshapiro			break;
416538032Speter		}
416638032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
416738032Speter			p++;
416838032Speter		if (*p != '\0')
416938032Speter			*p++ = '\0';
417038032Speter	}
417138032Speter	if (map->map_app != NULL)
417238032Speter		map->map_app = newstr(map->map_app);
417338032Speter	if (map->map_tapp != NULL)
417438032Speter		map->map_tapp = newstr(map->map_tapp);
417590792Sgshapiro	return true;
417638032Speter}
417790792Sgshapiro
417864562Sgshapiro#if NETINET6
417964562Sgshapiro/*
418064562Sgshapiro**  ANYNET_NTOP -- convert an IPv6 network address to printable form.
418164562Sgshapiro**
418264562Sgshapiro**	Parameters:
418364562Sgshapiro**		s6a -- a pointer to an in6_addr structure.
418464562Sgshapiro**		dst -- buffer to store result in
418564562Sgshapiro**		dst_len -- size of dst buffer
418664562Sgshapiro**
418764562Sgshapiro**	Returns:
418864562Sgshapiro**		A printable version of that structure.
418964562Sgshapiro*/
419090792Sgshapiro
419164562Sgshapirochar *
419264562Sgshapiroanynet_ntop(s6a, dst, dst_len)
419364562Sgshapiro	struct in6_addr *s6a;
419464562Sgshapiro	char *dst;
419564562Sgshapiro	size_t dst_len;
419664562Sgshapiro{
419764562Sgshapiro	register char *ap;
419864562Sgshapiro
419964562Sgshapiro	if (IN6_IS_ADDR_V4MAPPED(s6a))
420064562Sgshapiro		ap = (char *) inet_ntop(AF_INET,
420164562Sgshapiro					&s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
420264562Sgshapiro					dst, dst_len);
420364562Sgshapiro	else
420490792Sgshapiro	{
420590792Sgshapiro		char *d;
420690792Sgshapiro		size_t sz;
420790792Sgshapiro
420890792Sgshapiro		/* Save pointer to beginning of string */
420990792Sgshapiro		d = dst;
421090792Sgshapiro
421190792Sgshapiro		/* Add IPv6: protocol tag */
421290792Sgshapiro		sz = sm_strlcpy(dst, "IPv6:", dst_len);
421390792Sgshapiro		if (sz >= dst_len)
421490792Sgshapiro			return NULL;
421590792Sgshapiro		dst += sz;
421690792Sgshapiro		dst_len -= sz;
421764562Sgshapiro		ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
421890792Sgshapiro
421990792Sgshapiro		/* Restore pointer to beginning of string */
422090792Sgshapiro		if (ap != NULL)
422190792Sgshapiro			ap = d;
422290792Sgshapiro	}
422364562Sgshapiro	return ap;
422464562Sgshapiro}
422590792Sgshapiro
422690792Sgshapiro/*
422790792Sgshapiro**  ANYNET_PTON -- convert printed form to network address.
422890792Sgshapiro**
422990792Sgshapiro**	Wrapper for inet_pton() which handles IPv6: labels.
423090792Sgshapiro**
423190792Sgshapiro**	Parameters:
423290792Sgshapiro**		family -- address family
423390792Sgshapiro**		src -- string
423490792Sgshapiro**		dst -- destination address structure
423590792Sgshapiro**
423690792Sgshapiro**	Returns:
423790792Sgshapiro**		1 if the address was valid
423890792Sgshapiro**		0 if the address wasn't parseable
423990792Sgshapiro**		-1 if error
424090792Sgshapiro*/
424190792Sgshapiro
424290792Sgshapiroint
424390792Sgshapiroanynet_pton(family, src, dst)
424490792Sgshapiro	int family;
424590792Sgshapiro	const char *src;
424690792Sgshapiro	void *dst;
424790792Sgshapiro{
424890792Sgshapiro	if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0)
424990792Sgshapiro		src += 5;
425090792Sgshapiro	return inet_pton(family, src, dst);
425190792Sgshapiro}
425264562Sgshapiro#endif /* NETINET6 */
425390792Sgshapiro/*
425438032Speter**  ANYNET_NTOA -- convert a network address to printable form.
425538032Speter**
425638032Speter**	Parameters:
425738032Speter**		sap -- a pointer to a sockaddr structure.
425838032Speter**
425938032Speter**	Returns:
426038032Speter**		A printable version of that sockaddr.
426138032Speter*/
426238032Speter
426338032Speter#ifdef USE_SOCK_STREAM
426438032Speter
426564562Sgshapiro# if NETLINK
426664562Sgshapiro#  include <net/if_dl.h>
426764562Sgshapiro# endif /* NETLINK */
426838032Speter
426938032Speterchar *
427038032Speteranynet_ntoa(sap)
427138032Speter	register SOCKADDR *sap;
427238032Speter{
427338032Speter	register char *bp;
427438032Speter	register char *ap;
427538032Speter	int l;
427638032Speter	static char buf[100];
427738032Speter
427838032Speter	/* check for null/zero family */
427938032Speter	if (sap == NULL)
428038032Speter		return "NULLADDR";
428138032Speter	if (sap->sa.sa_family == 0)
428238032Speter		return "0";
428338032Speter
428438032Speter	switch (sap->sa.sa_family)
428538032Speter	{
428664562Sgshapiro# if NETUNIX
428738032Speter	  case AF_UNIX:
428864562Sgshapiro		if (sap->sunix.sun_path[0] != '\0')
428990792Sgshapiro			(void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]",
429090792Sgshapiro					   sap->sunix.sun_path);
429164562Sgshapiro		else
429290792Sgshapiro			(void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf);
429338032Speter		return buf;
429464562Sgshapiro# endif /* NETUNIX */
429538032Speter
429664562Sgshapiro# if NETINET
429738032Speter	  case AF_INET:
429864562Sgshapiro		return (char *) inet_ntoa(sap->sin.sin_addr);
429964562Sgshapiro# endif /* NETINET */
430038032Speter
430164562Sgshapiro# if NETINET6
430264562Sgshapiro	  case AF_INET6:
430364562Sgshapiro		ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf);
430464562Sgshapiro		if (ap != NULL)
430564562Sgshapiro			return ap;
430664562Sgshapiro		break;
430764562Sgshapiro# endif /* NETINET6 */
430864562Sgshapiro
430964562Sgshapiro# if NETLINK
431038032Speter	  case AF_LINK:
431190792Sgshapiro		(void) sm_snprintf(buf, sizeof buf, "[LINK: %s]",
431290792Sgshapiro				   link_ntoa((struct sockaddr_dl *) &sap->sa));
431338032Speter		return buf;
431464562Sgshapiro# endif /* NETLINK */
431538032Speter	  default:
431638032Speter		/* this case is needed when nothing is #defined */
431738032Speter		/* in order to keep the switch syntactically correct */
431838032Speter		break;
431938032Speter	}
432038032Speter
432138032Speter	/* unknown family -- just dump bytes */
432290792Sgshapiro	(void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
432338032Speter	bp = &buf[strlen(buf)];
432438032Speter	ap = sap->sa.sa_data;
432538032Speter	for (l = sizeof sap->sa.sa_data; --l >= 0; )
432638032Speter	{
432790792Sgshapiro		(void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:",
432890792Sgshapiro				   *ap++ & 0377);
432938032Speter		bp += 3;
433038032Speter	}
433138032Speter	*--bp = '\0';
433238032Speter	return buf;
433338032Speter}
433490792Sgshapiro/*
433538032Speter**  HOSTNAMEBYANYADDR -- return name of host based on address
433638032Speter**
433738032Speter**	Parameters:
433838032Speter**		sap -- SOCKADDR pointer
433938032Speter**
434038032Speter**	Returns:
434138032Speter**		text representation of host name.
434238032Speter**
434338032Speter**	Side Effects:
434438032Speter**		none.
434538032Speter*/
434638032Speter
434738032Speterchar *
434838032Speterhostnamebyanyaddr(sap)
434938032Speter	register SOCKADDR *sap;
435038032Speter{
435138032Speter	register struct hostent *hp;
435264562Sgshapiro# if NAMED_BIND
435338032Speter	int saveretry;
435464562Sgshapiro# endif /* NAMED_BIND */
435564562Sgshapiro# if NETINET6
435664562Sgshapiro	struct in6_addr in6_addr;
435764562Sgshapiro# endif /* NETINET6 */
435838032Speter
435964562Sgshapiro# if NAMED_BIND
436038032Speter	/* shorten name server timeout to avoid higher level timeouts */
436138032Speter	saveretry = _res.retry;
436264562Sgshapiro	if (_res.retry * _res.retrans > 20)
436364562Sgshapiro		_res.retry = 20 / _res.retrans;
436464562Sgshapiro# endif /* NAMED_BIND */
436538032Speter
436638032Speter	switch (sap->sa.sa_family)
436738032Speter	{
436864562Sgshapiro# if NETINET
436938032Speter	  case AF_INET:
437038032Speter		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
437190792Sgshapiro				      INADDRSZ, AF_INET);
437238032Speter		break;
437364562Sgshapiro# endif /* NETINET */
437438032Speter
437564562Sgshapiro# if NETINET6
437664562Sgshapiro	  case AF_INET6:
437764562Sgshapiro		hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
437890792Sgshapiro				      IN6ADDRSZ, AF_INET6);
437964562Sgshapiro		break;
438064562Sgshapiro# endif /* NETINET6 */
438164562Sgshapiro
438264562Sgshapiro# if NETISO
438338032Speter	  case AF_ISO:
438438032Speter		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
438590792Sgshapiro				      sizeof sap->siso.siso_addr, AF_ISO);
438638032Speter		break;
438764562Sgshapiro# endif /* NETISO */
438838032Speter
438964562Sgshapiro# if NETUNIX
439038032Speter	  case AF_UNIX:
439138032Speter		hp = NULL;
439238032Speter		break;
439364562Sgshapiro# endif /* NETUNIX */
439438032Speter
439538032Speter	  default:
439690792Sgshapiro		hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data,
439790792Sgshapiro				      sap->sa.sa_family);
439838032Speter		break;
439938032Speter	}
440038032Speter
440164562Sgshapiro# if NAMED_BIND
440238032Speter	_res.retry = saveretry;
440364562Sgshapiro# endif /* NAMED_BIND */
440438032Speter
440564562Sgshapiro# if NETINET || NETINET6
440664562Sgshapiro	if (hp != NULL && hp->h_name[0] != '['
440764562Sgshapiro#  if NETINET6
440864562Sgshapiro	    && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1
440964562Sgshapiro#  endif /* NETINET6 */
441064562Sgshapiro#  if NETINET
441164562Sgshapiro	    && inet_addr(hp->h_name) == INADDR_NONE
441264562Sgshapiro#  endif /* NETINET */
441364562Sgshapiro	    )
441471345Sgshapiro	{
441571345Sgshapiro		char *name;
441671345Sgshapiro
441790792Sgshapiro		name = denlstring((char *) hp->h_name, true, true);
441890792Sgshapiro#  if NETINET6
441971345Sgshapiro		if (name == hp->h_name)
442071345Sgshapiro		{
442171345Sgshapiro			static char n[MAXNAME + 1];
442271345Sgshapiro
442371345Sgshapiro			/* Copy the string, hp->h_name is about to disappear */
442490792Sgshapiro			(void) sm_strlcpy(n, name, sizeof n);
442571345Sgshapiro			name = n;
442671345Sgshapiro		}
442771345Sgshapiro		freehostent(hp);
442890792Sgshapiro#  endif /* NETINET6 */
442971345Sgshapiro		return name;
443071345Sgshapiro	}
443164562Sgshapiro# endif /* NETINET || NETINET6 */
443271345Sgshapiro
443390792Sgshapiro# if NETINET6
443471345Sgshapiro	if (hp != NULL)
443571345Sgshapiro	{
443671345Sgshapiro		freehostent(hp);
443771345Sgshapiro		hp = NULL;
443871345Sgshapiro	}
443990792Sgshapiro# endif /* NETINET6 */
444071345Sgshapiro
444164562Sgshapiro# if NETUNIX
444264562Sgshapiro	if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
444338032Speter		return "localhost";
444464562Sgshapiro# endif /* NETUNIX */
444538032Speter	{
444638032Speter		static char buf[203];
444738032Speter
444890792Sgshapiro		(void) sm_snprintf(buf, sizeof buf, "[%.200s]",
444990792Sgshapiro				   anynet_ntoa(sap));
445038032Speter		return buf;
445138032Speter	}
445238032Speter}
445364562Sgshapiro#endif /* USE_SOCK_STREAM */
4454