daemon.c revision 80785
138032Speter/*
273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
1664562Sgshapiro
1738032Speter#ifndef lint
1864562Sgshapiro# ifdef DAEMON
1980785Sgshapirostatic char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro Exp $ (with daemon mode)";
2064562Sgshapiro# else /* DAEMON */
2180785Sgshapirostatic char id[] = "@(#)$Id: daemon.c,v 8.401.4.68 2001/07/20 18:45:58 gshapiro Exp $ (without daemon mode)";
2264562Sgshapiro# endif /* DAEMON */
2364562Sgshapiro#endif /* ! lint */
2438032Speter
2538032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
2638032Speter# define USE_SOCK_STREAM	1
2764562Sgshapiro#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
2838032Speter
2938032Speter#if DAEMON || defined(USE_SOCK_STREAM)
3064562Sgshapiro# if NETINET || NETINET6
3164562Sgshapiro#  include <arpa/inet.h>
3264562Sgshapiro# endif /* NETINET || NETINET6 */
3338032Speter# if NAMED_BIND
3438032Speter#  ifndef NO_DATA
3538032Speter#   define NO_DATA	NO_ADDRESS
3664562Sgshapiro#  endif /* ! NO_DATA */
3764562Sgshapiro# endif /* NAMED_BIND */
3864562Sgshapiro#endif /* DAEMON || defined(USE_SOCK_STREAM) */
3938032Speter
4038032Speter#if DAEMON
4138032Speter
4266494Sgshapiro# if STARTTLS
4366494Sgshapiro#    include <openssl/rand.h>
4466494Sgshapiro# endif /* STARTTLS */
4566494Sgshapiro
4638032Speter# include <sys/time.h>
4738032Speter
4864562Sgshapiro# if IP_SRCROUTE && NETINET
4938032Speter#  include <netinet/in_systm.h>
5038032Speter#  include <netinet/ip.h>
5164562Sgshapiro#  if HAS_IN_H
5264562Sgshapiro#   include <netinet/in.h>
5364562Sgshapiro#   ifndef IPOPTION
5464562Sgshapiro#    define IPOPTION	ip_opts
5564562Sgshapiro#    define IP_LIST	ip_opts
5664562Sgshapiro#    define IP_DST	ip_dst
5764562Sgshapiro#   endif /* ! IPOPTION */
5864562Sgshapiro#  else /* HAS_IN_H */
5964562Sgshapiro#   include <netinet/ip_var.h>
6064562Sgshapiro#   ifndef IPOPTION
6164562Sgshapiro#    define IPOPTION	ipoption
6264562Sgshapiro#    define IP_LIST	ipopt_list
6364562Sgshapiro#    define IP_DST	ipopt_dst
6464562Sgshapiro#   endif /* ! IPOPTION */
6564562Sgshapiro#  endif /* HAS_IN_H */
6664562Sgshapiro# endif /* IP_SRCROUTE && NETINET */
6738032Speter
6864562Sgshapiro/* structure to describe a daemon */
6964562Sgshapirostruct daemon
7064562Sgshapiro{
7164562Sgshapiro	int		d_socket;	/* fd for socket */
7264562Sgshapiro	SOCKADDR	d_addr;		/* socket for incoming */
7364562Sgshapiro	u_short		d_port;		/* port number */
7464562Sgshapiro	int		d_listenqueue;	/* size of listen queue */
7564562Sgshapiro	int		d_tcprcvbufsize;	/* size of TCP receive buffer */
7664562Sgshapiro	int		d_tcpsndbufsize;	/* size of TCP send buffer */
7764562Sgshapiro	time_t		d_refuse_connections_until;
7864562Sgshapiro	bool		d_firsttime;
7964562Sgshapiro	int		d_socksize;
8064562Sgshapiro	BITMAP256	d_flags;	/* flags; see sendmail.h */
8164562Sgshapiro	char		*d_mflags;	/* flags for use in macro */
8264562Sgshapiro	char		*d_name;	/* user-supplied name */
8364562Sgshapiro};
8464562Sgshapiro
8564562Sgshapirotypedef struct daemon DAEMON_T;
8664562Sgshapiro
8764562Sgshapirostatic void	connecttimeout __P((void));
8864562Sgshapirostatic int	opendaemonsocket __P((struct daemon *, bool));
8964562Sgshapirostatic u_short	setupdaemon __P((SOCKADDR *));
9077349Sgshapirostatic SIGFUNC_DECL	sighup __P((int));
9177349Sgshapirostatic void	restart_daemon __P((void));
9264562Sgshapiro
9338032Speter/*
9438032Speter**  DAEMON.C -- routines to use when running as a daemon.
9538032Speter**
9638032Speter**	This entire file is highly dependent on the 4.2 BSD
9738032Speter**	interprocess communication primitives.  No attempt has
9838032Speter**	been made to make this file portable to Version 7,
9938032Speter**	Version 6, MPX files, etc.  If you should try such a
10038032Speter**	thing yourself, I recommend chucking the entire file
10138032Speter**	and starting from scratch.  Basic semantics are:
10238032Speter**
10338032Speter**	getrequests(e)
10438032Speter**		Opens a port and initiates a connection.
10538032Speter**		Returns in a child.  Must set InChannel and
10638032Speter**		OutChannel appropriately.
10738032Speter**	clrdaemon()
10838032Speter**		Close any open files associated with getting
10938032Speter**		the connection; this is used when running the queue,
11038032Speter**		etc., to avoid having extra file descriptors during
11138032Speter**		the queue run and to avoid confusing the network
11238032Speter**		code (if it cares).
11338032Speter**	makeconnection(host, port, outfile, infile, e)
11438032Speter**		Make a connection to the named host on the given
11538032Speter**		port.  Set *outfile and *infile to the files
11638032Speter**		appropriate for communication.  Returns zero on
11738032Speter**		success, else an exit status describing the
11838032Speter**		error.
11938032Speter**	host_map_lookup(map, hbuf, avp, pstat)
12038032Speter**		Convert the entry in hbuf into a canonical form.
12138032Speter*/
12264562Sgshapiro
12364562Sgshapirostatic DAEMON_T	Daemons[MAXDAEMONS];
12464562Sgshapirostatic int	ndaemons = 0;			/* actual number of daemons */
12564562Sgshapiro
12664562Sgshapiro/* options for client */
12764562Sgshapirostatic int	TcpRcvBufferSize = 0;	/* size of TCP receive buffer */
12864562Sgshapirostatic int	TcpSndBufferSize = 0;	/* size of TCP send buffer */
12964562Sgshapiro
13038032Speter/*
13138032Speter**  GETREQUESTS -- open mail IPC port and get requests.
13238032Speter**
13338032Speter**	Parameters:
13438032Speter**		e -- the current envelope.
13538032Speter**
13638032Speter**	Returns:
13764562Sgshapiro**		pointer to flags.
13838032Speter**
13938032Speter**	Side Effects:
14038032Speter**		Waits until some interesting activity occurs.  When
14138032Speter**		it does, a child is created to process it, and the
14238032Speter**		parent waits for completion.  Return from this
14338032Speter**		routine is always in the child.  The file pointers
14438032Speter**		"InChannel" and "OutChannel" should be set to point
14538032Speter**		to the communication channel.
14638032Speter*/
14738032Speter
14864562SgshapiroBITMAP256 *
14938032Spetergetrequests(e)
15038032Speter	ENVELOPE *e;
15138032Speter{
15238032Speter	int t;
15364562Sgshapiro	time_t last_disk_space_check = 0;
15464562Sgshapiro	int idx, curdaemon = -1;
15564562Sgshapiro	int i, olddaemon = 0;
15664562Sgshapiro# if XDEBUG
15738032Speter	bool j_has_dot;
15864562Sgshapiro# endif /* XDEBUG */
15942575Speter	char status[MAXLINE];
16064562Sgshapiro	SOCKADDR sa;
16164562Sgshapiro	SOCKADDR_LEN_T len = sizeof sa;
16264562Sgshapiro# if NETUNIX
16342575Speter	extern int ControlSocket;
16464562Sgshapiro# endif /* NETUNIX */
16564562Sgshapiro	extern ENVELOPE BlankEnvelope;
16638032Speter
16738032Speter
16864562Sgshapiro	for (idx = 0; idx < ndaemons; idx++)
16938032Speter	{
17064562Sgshapiro		Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
17164562Sgshapiro		Daemons[idx].d_firsttime = TRUE;
17264562Sgshapiro		Daemons[idx].d_refuse_connections_until = (time_t) 0;
17338032Speter	}
17471345Sgshapiro
17538032Speter	/*
17638032Speter	**  Try to actually open the connection.
17738032Speter	*/
17838032Speter
17938032Speter	if (tTd(15, 1))
18064562Sgshapiro	{
18164562Sgshapiro		for (idx = 0; idx < ndaemons; idx++)
18271345Sgshapiro		{
18364562Sgshapiro			dprintf("getrequests: daemon %s: port %d\n",
18464562Sgshapiro				Daemons[idx].d_name,
18564562Sgshapiro				ntohs(Daemons[idx].d_port));
18671345Sgshapiro		}
18764562Sgshapiro	}
18838032Speter
18938032Speter	/* get a socket for the SMTP connection */
19064562Sgshapiro	for (idx = 0; idx < ndaemons; idx++)
19164562Sgshapiro		Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], TRUE);
19238032Speter
19342575Speter	if (opencontrolsocket() < 0)
19442575Speter		sm_syslog(LOG_WARNING, NOQID,
19543730Speter			  "daemon could not open control socket %s: %s",
19643730Speter			  ControlSocketName, errstring(errno));
19742575Speter
19838032Speter	(void) setsignal(SIGCHLD, reapchild);
19977349Sgshapiro	(void) setsignal(SIGHUP, sighup);
20038032Speter
20177349Sgshapiro	/* workaround: can't seem to release the signal in the parent */
20277349Sgshapiro	(void) releasesignal(SIGHUP);
20377349Sgshapiro
20464562Sgshapiro	/* write the pid to file */
20564562Sgshapiro	log_sendmail_pid(e);
20638032Speter
20764562Sgshapiro# if XDEBUG
20838032Speter	{
20938032Speter		char jbuf[MAXHOSTNAMELEN];
21038032Speter
21138032Speter		expand("\201j", jbuf, sizeof jbuf, e);
21238032Speter		j_has_dot = strchr(jbuf, '.') != NULL;
21338032Speter	}
21464562Sgshapiro# endif /* XDEBUG */
21538032Speter
21642575Speter	/* Add parent process as first item */
21764562Sgshapiro	proc_list_add(getpid(), "Sendmail daemon", PROC_DAEMON);
21842575Speter
21938032Speter	if (tTd(15, 1))
22064562Sgshapiro	{
22164562Sgshapiro		for (idx = 0; idx < ndaemons; idx++)
22264562Sgshapiro			dprintf("getrequests: daemon %s: %d\n",
22364562Sgshapiro				Daemons[idx].d_name,
22464562Sgshapiro				Daemons[idx].d_socket);
22564562Sgshapiro	}
22638032Speter
22738032Speter	for (;;)
22838032Speter	{
22938032Speter		register pid_t pid;
23038032Speter		auto SOCKADDR_LEN_T lotherend;
23142575Speter		bool timedout = FALSE;
23242575Speter		bool control = FALSE;
23364562Sgshapiro		int save_errno;
23438032Speter		int pipefd[2];
23571345Sgshapiro		time_t timenow;
23666494Sgshapiro# if STARTTLS
23766494Sgshapiro		long seed;
23866494Sgshapiro# endif /* STARTTLS */
23971345Sgshapiro		extern bool refuseconnections __P((char *, ENVELOPE *, int));
24038032Speter
24138032Speter		/* see if we are rejecting connections */
24238032Speter		(void) blocksignal(SIGALRM);
24364562Sgshapiro
24477349Sgshapiro		if (ShutdownRequest != NULL)
24577349Sgshapiro			shutdown_daemon();
24677349Sgshapiro		else if (RestartRequest != NULL)
24777349Sgshapiro			restart_daemon();
24877349Sgshapiro
24971345Sgshapiro		timenow = curtime();
25071345Sgshapiro
25171345Sgshapiro		/*
25271345Sgshapiro		**  Use ConnRateThrottle only if the
25371345Sgshapiro		**  last pass was for a connection
25471345Sgshapiro		*/
25571345Sgshapiro
25671345Sgshapiro		if (ConnRateThrottle > 0 && curdaemon >= 0)
25771345Sgshapiro		{
25871345Sgshapiro			static int conncnt = 0;
25971345Sgshapiro			static time_t lastconn = 0;
26071345Sgshapiro
26171345Sgshapiro			if (timenow != lastconn)
26271345Sgshapiro			{
26371345Sgshapiro				lastconn = timenow;
26471345Sgshapiro				conncnt = 1;
26571345Sgshapiro			}
26671345Sgshapiro			else if (++conncnt > ConnRateThrottle)
26771345Sgshapiro			{
26871345Sgshapiro				/* sleep to flatten out connection load */
26971345Sgshapiro				sm_setproctitle(TRUE, e,
27071345Sgshapiro						"deferring connections: %d per second",
27171345Sgshapiro						ConnRateThrottle);
27271345Sgshapiro				if (LogLevel >= 9)
27371345Sgshapiro					sm_syslog(LOG_INFO, NOQID,
27471345Sgshapiro						  "deferring connections: %d per second",
27571345Sgshapiro						  ConnRateThrottle);
27671345Sgshapiro				(void) sleep(1);
27771345Sgshapiro			}
27871345Sgshapiro		}
27971345Sgshapiro
28064562Sgshapiro		for (idx = 0; idx < ndaemons; idx++)
28138032Speter		{
28271345Sgshapiro			if (timenow < Daemons[idx].d_refuse_connections_until)
28364562Sgshapiro				continue;
28464562Sgshapiro			if (refuseconnections(Daemons[idx].d_name, e, idx))
28538032Speter			{
28664562Sgshapiro				if (Daemons[idx].d_socket >= 0)
28742575Speter				{
28871345Sgshapiro					/* close socket so peer fails quickly */
28971345Sgshapiro					(void) close(Daemons[idx].d_socket);
29071345Sgshapiro					Daemons[idx].d_socket = -1;
29142575Speter				}
29242575Speter
29342575Speter				/* refuse connections for next 15 seconds */
29471345Sgshapiro				Daemons[idx].d_refuse_connections_until = timenow + 15;
29538032Speter			}
29664562Sgshapiro			else if (Daemons[idx].d_socket < 0 ||
29764562Sgshapiro				 Daemons[idx].d_firsttime)
29842575Speter			{
29971345Sgshapiro				if (!Daemons[idx].d_firsttime && LogLevel >= 9)
30071345Sgshapiro					sm_syslog(LOG_INFO, NOQID,
30171345Sgshapiro						"accepting connections again for daemon %s",
30271345Sgshapiro						Daemons[idx].d_name);
30364562Sgshapiro
30471345Sgshapiro				/* arrange to (re)open the socket if needed */
30571345Sgshapiro				(void) opendaemonsocket(&Daemons[idx], FALSE);
30671345Sgshapiro				Daemons[idx].d_firsttime = FALSE;
30742575Speter			}
30838032Speter		}
30938032Speter
31077349Sgshapiro		/* May have been sleeping above, check again */
31177349Sgshapiro		if (ShutdownRequest != NULL)
31277349Sgshapiro			shutdown_daemon();
31377349Sgshapiro		else if (RestartRequest != NULL)
31477349Sgshapiro			restart_daemon();
31577349Sgshapiro
31671345Sgshapiro		if (timenow >= last_disk_space_check)
31764562Sgshapiro		{
31871345Sgshapiro			bool logged = FALSE;
31971345Sgshapiro
32064562Sgshapiro			if (!enoughdiskspace(MinBlocksFree + 1, FALSE))
32164562Sgshapiro			{
32271345Sgshapiro				for (idx = 0; idx < ndaemons; idx++)
32364562Sgshapiro				{
32471345Sgshapiro					if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
32571345Sgshapiro					{
32671345Sgshapiro						/* log only if not logged before */
32771345Sgshapiro						if (!logged)
32871345Sgshapiro						{
32971345Sgshapiro							if (LogLevel >= 9)
33071345Sgshapiro								sm_syslog(LOG_INFO, NOQID,
33171345Sgshapiro									  "rejecting new messages: min free: %ld",
33271345Sgshapiro									  MinBlocksFree);
33371345Sgshapiro							logged = TRUE;
33471345Sgshapiro							sm_setproctitle(TRUE, e,
33571345Sgshapiro									"rejecting new messages: min free: %ld",
33671345Sgshapiro									MinBlocksFree);
33771345Sgshapiro						}
33871345Sgshapiro						setbitn(D_ETRNONLY, Daemons[idx].d_flags);
33971345Sgshapiro					}
34064562Sgshapiro				}
34164562Sgshapiro			}
34271345Sgshapiro			else
34364562Sgshapiro			{
34471345Sgshapiro				for (idx = 0; idx < ndaemons; idx++)
34571345Sgshapiro				{
34671345Sgshapiro					if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
34771345Sgshapiro					{
34871345Sgshapiro						/* log only if not logged before */
34971345Sgshapiro						if (!logged)
35071345Sgshapiro						{
35171345Sgshapiro							if (LogLevel >= 9)
35271345Sgshapiro								sm_syslog(LOG_INFO, NOQID,
35371345Sgshapiro									  "accepting new messages (again)");
35471345Sgshapiro							logged = TRUE;
35571345Sgshapiro						}
35671345Sgshapiro
35771345Sgshapiro						/* title will be set below */
35871345Sgshapiro						clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
35971345Sgshapiro					}
36071345Sgshapiro				}
36164562Sgshapiro			}
36264562Sgshapiro			/* only check disk space once a minute */
36371345Sgshapiro			last_disk_space_check = timenow + 60;
36464562Sgshapiro		}
36564562Sgshapiro
36664562Sgshapiro# if XDEBUG
36738032Speter		/* check for disaster */
36838032Speter		{
36938032Speter			char jbuf[MAXHOSTNAMELEN];
37038032Speter
37138032Speter			expand("\201j", jbuf, sizeof jbuf, e);
37238032Speter			if (!wordinclass(jbuf, 'w'))
37338032Speter			{
37438032Speter				dumpstate("daemon lost $j");
37538032Speter				sm_syslog(LOG_ALERT, NOQID,
37664562Sgshapiro					  "daemon process doesn't have $j in $=w; see syslog");
37738032Speter				abort();
37838032Speter			}
37938032Speter			else if (j_has_dot && strchr(jbuf, '.') == NULL)
38038032Speter			{
38138032Speter				dumpstate("daemon $j lost dot");
38238032Speter				sm_syslog(LOG_ALERT, NOQID,
38364562Sgshapiro					  "daemon process $j lost dot; see syslog");
38438032Speter				abort();
38538032Speter			}
38638032Speter		}
38764562Sgshapiro# endif /* XDEBUG */
38838032Speter
38964562Sgshapiro# if 0
39038032Speter		/*
39138032Speter		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
39238032Speter		**  fix the SVr4 problem.  But it seems to have gone away,
39338032Speter		**  so is it worth doing this?
39438032Speter		*/
39538032Speter
39642575Speter		if (DaemonSocket >= 0 &&
39742575Speter		    SetNonBlocking(DaemonSocket, FALSE) < 0)
39838032Speter			log an error here;
39964562Sgshapiro# endif /* 0 */
40038032Speter		(void) releasesignal(SIGALRM);
40164562Sgshapiro
40238032Speter		for (;;)
40338032Speter		{
40471345Sgshapiro			bool setproc = FALSE;
40542575Speter			int highest = -1;
40638032Speter			fd_set readfds;
40738032Speter			struct timeval timeout;
40838032Speter
40977349Sgshapiro			if (ShutdownRequest != NULL)
41077349Sgshapiro				shutdown_daemon();
41177349Sgshapiro			else if (RestartRequest != NULL)
41277349Sgshapiro				restart_daemon();
41377349Sgshapiro
41438032Speter			FD_ZERO(&readfds);
41542575Speter
41664562Sgshapiro			for (idx = 0; idx < ndaemons; idx++)
41742575Speter			{
41864562Sgshapiro				/* wait for a connection */
41964562Sgshapiro				if (Daemons[idx].d_socket >= 0)
42064562Sgshapiro				{
42171345Sgshapiro					if (!setproc &&
42271345Sgshapiro					    !bitnset(D_ETRNONLY,
42371345Sgshapiro						     Daemons[idx].d_flags))
42464562Sgshapiro					{
42564562Sgshapiro						sm_setproctitle(TRUE, e,
42664562Sgshapiro								"accepting connections");
42771345Sgshapiro						setproc = TRUE;
42864562Sgshapiro					}
42964562Sgshapiro					if (Daemons[idx].d_socket > highest)
43064562Sgshapiro						highest = Daemons[idx].d_socket;
43164562Sgshapiro					FD_SET((u_int)Daemons[idx].d_socket, &readfds);
43264562Sgshapiro				}
43342575Speter			}
43464562Sgshapiro
43564562Sgshapiro# if NETUNIX
43642575Speter			if (ControlSocket >= 0)
43742575Speter			{
43842575Speter				if (ControlSocket > highest)
43942575Speter					highest = ControlSocket;
44042575Speter				FD_SET(ControlSocket, &readfds);
44142575Speter			}
44264562Sgshapiro# endif /* NETUNIX */
44364562Sgshapiro
44477349Sgshapiro			timeout.tv_sec = 5;
44538032Speter			timeout.tv_usec = 0;
44638032Speter
44742575Speter			t = select(highest + 1, FDSET_CAST &readfds,
44864562Sgshapiro				   NULL, NULL, &timeout);
44942575Speter
45077349Sgshapiro			/* Did someone signal while waiting? */
45177349Sgshapiro			if (ShutdownRequest != NULL)
45277349Sgshapiro				shutdown_daemon();
45377349Sgshapiro			else if (RestartRequest != NULL)
45477349Sgshapiro				restart_daemon();
45571345Sgshapiro
45671345Sgshapiro
45777349Sgshapiro
45838032Speter			if (DoQueueRun)
45938032Speter				(void) runqueue(TRUE, FALSE);
46071345Sgshapiro
46171345Sgshapiro			curdaemon = -1;
46242575Speter			if (t <= 0)
46342575Speter			{
46442575Speter				timedout = TRUE;
46542575Speter				break;
46642575Speter			}
46738032Speter
46842575Speter			control = FALSE;
46938032Speter			errno = 0;
47064562Sgshapiro
47164562Sgshapiro			/* look "round-robin" for an active socket */
47264562Sgshapiro			if ((idx = olddaemon + 1) >= ndaemons)
47364562Sgshapiro				idx = 0;
47464562Sgshapiro			for (i = 0; i < ndaemons; i++)
47542575Speter			{
47664562Sgshapiro				if (Daemons[idx].d_socket >= 0 &&
47764562Sgshapiro				    FD_ISSET(Daemons[idx].d_socket, &readfds))
47864562Sgshapiro				{
47964562Sgshapiro					lotherend = Daemons[idx].d_socksize;
48073188Sgshapiro					memset(&RealHostAddr, '\0',
48173188Sgshapiro					       sizeof RealHostAddr);
48264562Sgshapiro					t = accept(Daemons[idx].d_socket,
48364562Sgshapiro						   (struct sockaddr *)&RealHostAddr,
48464562Sgshapiro						   &lotherend);
48573188Sgshapiro
48673188Sgshapiro					/*
48773188Sgshapiro					**  If remote side closes before
48873188Sgshapiro					**  accept() finishes, sockaddr
48973188Sgshapiro					**  might not be fully filled in.
49073188Sgshapiro					*/
49173188Sgshapiro
49273188Sgshapiro					if (t >= 0 &&
49373188Sgshapiro					    (lotherend == 0 ||
49473188Sgshapiro# ifdef BSD4_4_SOCKADDR
49573188Sgshapiro					     RealHostAddr.sa.sa_len == 0 ||
49673188Sgshapiro# endif /* BSD4_4_SOCKADDR */
49773188Sgshapiro					     RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family))
49873188Sgshapiro					{
49973188Sgshapiro						(void) close(t);
50073188Sgshapiro						t = -1;
50173188Sgshapiro						errno = EINVAL;
50273188Sgshapiro					}
50364562Sgshapiro					olddaemon = curdaemon = idx;
50464562Sgshapiro					break;
50564562Sgshapiro				}
50664562Sgshapiro				if (++idx >= ndaemons)
50764562Sgshapiro					idx = 0;
50842575Speter			}
50964562Sgshapiro# if NETUNIX
51064562Sgshapiro			if (curdaemon == -1 && ControlSocket >= 0 &&
51171345Sgshapiro			    FD_ISSET(ControlSocket, &readfds))
51242575Speter			{
51342575Speter				struct sockaddr_un sa_un;
51442575Speter
51542575Speter				lotherend = sizeof sa_un;
51673188Sgshapiro				memset(&sa_un, '\0', sizeof sa_un);
51742575Speter				t = accept(ControlSocket,
51842575Speter					   (struct sockaddr *)&sa_un,
51942575Speter					   &lotherend);
52073188Sgshapiro
52173188Sgshapiro				/*
52273188Sgshapiro				**  If remote side closes before
52373188Sgshapiro				**  accept() finishes, sockaddr
52473188Sgshapiro				**  might not be fully filled in.
52573188Sgshapiro				*/
52673188Sgshapiro
52773188Sgshapiro				if (t >= 0 &&
52873188Sgshapiro				    (lotherend == 0 ||
52973188Sgshapiro# ifdef BSD4_4_SOCKADDR
53073188Sgshapiro				     sa_un.sun_len == 0 ||
53173188Sgshapiro# endif /* BSD4_4_SOCKADDR */
53273188Sgshapiro				     sa_un.sun_family != AF_UNIX))
53373188Sgshapiro				{
53473188Sgshapiro					(void) close(t);
53573188Sgshapiro					t = -1;
53673188Sgshapiro					errno = EINVAL;
53773188Sgshapiro				}
53873188Sgshapiro				if (t >= 0)
53973188Sgshapiro					control = TRUE;
54042575Speter			}
54171345Sgshapiro# else /* NETUNIX */
54271345Sgshapiro			if (curdaemon == -1)
54371345Sgshapiro			{
54471345Sgshapiro				/* No daemon to service */
54571345Sgshapiro				continue;
54671345Sgshapiro			}
54764562Sgshapiro# endif /* NETUNIX */
54838032Speter			if (t >= 0 || errno != EINTR)
54938032Speter				break;
55038032Speter		}
55142575Speter		if (timedout)
55242575Speter		{
55342575Speter			timedout = FALSE;
55442575Speter			continue;
55542575Speter		}
55664562Sgshapiro		save_errno = errno;
55771345Sgshapiro		timenow = curtime();
55838032Speter		(void) blocksignal(SIGALRM);
55938032Speter		if (t < 0)
56038032Speter		{
56164562Sgshapiro			errno = save_errno;
56238032Speter			syserr("getrequests: accept");
56338032Speter
56438032Speter			/* arrange to re-open the socket next time around */
56564562Sgshapiro			(void) close(Daemons[curdaemon].d_socket);
56664562Sgshapiro			Daemons[curdaemon].d_socket = -1;
56764562Sgshapiro# if SO_REUSEADDR_IS_BROKEN
56864562Sgshapiro			/*
56964562Sgshapiro			**  Give time for bound socket to be released.
57064562Sgshapiro			**  This creates a denial-of-service if you can
57164562Sgshapiro			**  force accept() to fail on affected systems.
57264562Sgshapiro			*/
57364562Sgshapiro
57471345Sgshapiro			Daemons[curdaemon].d_refuse_connections_until = timenow + 15;
57564562Sgshapiro# endif /* SO_REUSEADDR_IS_BROKEN */
57638032Speter			continue;
57738032Speter		}
57838032Speter
57964562Sgshapiro		if (!control)
58064562Sgshapiro		{
58164562Sgshapiro			/* set some daemon related macros */
58264562Sgshapiro			switch (Daemons[curdaemon].d_addr.sa.sa_family)
58364562Sgshapiro			{
58464562Sgshapiro			  case AF_UNSPEC:
58564562Sgshapiro				define(macid("{daemon_family}", NULL),
58664562Sgshapiro				       "unspec", &BlankEnvelope);
58764562Sgshapiro				break;
58864562Sgshapiro# if NETINET
58964562Sgshapiro			  case AF_INET:
59064562Sgshapiro				define(macid("{daemon_family}", NULL),
59164562Sgshapiro				       "inet", &BlankEnvelope);
59264562Sgshapiro				break;
59364562Sgshapiro# endif /* NETINET */
59464562Sgshapiro# if NETINET6
59564562Sgshapiro			  case AF_INET6:
59664562Sgshapiro				define(macid("{daemon_family}", NULL),
59764562Sgshapiro				       "inet6", &BlankEnvelope);
59864562Sgshapiro				break;
59964562Sgshapiro# endif /* NETINET6 */
60064562Sgshapiro# if NETISO
60164562Sgshapiro			  case AF_ISO:
60264562Sgshapiro				define(macid("{daemon_family}", NULL),
60364562Sgshapiro				       "iso", &BlankEnvelope);
60464562Sgshapiro				break;
60564562Sgshapiro# endif /* NETISO */
60664562Sgshapiro# if NETNS
60764562Sgshapiro			  case AF_NS:
60864562Sgshapiro				define(macid("{daemon_family}", NULL),
60964562Sgshapiro				       "ns", &BlankEnvelope);
61064562Sgshapiro				break;
61164562Sgshapiro# endif /* NETNS */
61264562Sgshapiro# if NETX25
61364562Sgshapiro			  case AF_CCITT:
61464562Sgshapiro				define(macid("{daemon_family}", NULL),
61564562Sgshapiro				       "x.25", &BlankEnvelope);
61664562Sgshapiro				break;
61764562Sgshapiro# endif /* NETX25 */
61864562Sgshapiro			}
61964562Sgshapiro			define(macid("{daemon_name}", NULL),
62064562Sgshapiro			       Daemons[curdaemon].d_name, &BlankEnvelope);
62164562Sgshapiro			if (Daemons[curdaemon].d_mflags != NULL)
62264562Sgshapiro				define(macid("{daemon_flags}", NULL),
62364562Sgshapiro				       Daemons[curdaemon].d_mflags,
62464562Sgshapiro				       &BlankEnvelope);
62564562Sgshapiro			else
62664562Sgshapiro				define(macid("{daemon_flags}", NULL),
62764562Sgshapiro				       "", &BlankEnvelope);
62864562Sgshapiro		}
62964562Sgshapiro
63038032Speter		/*
63138032Speter		**  Create a subprocess to process the mail.
63238032Speter		*/
63338032Speter
63438032Speter		if (tTd(15, 2))
63564562Sgshapiro			dprintf("getrequests: forking (fd = %d)\n", t);
63638032Speter
63738032Speter		/*
63864562Sgshapiro		**  advance state of PRNG
63964562Sgshapiro		**  this is necessary because otherwise all child processes
64064562Sgshapiro		**  will produce the same PRN sequence and hence the selection
64164562Sgshapiro		**  of a queue directory (and other things, e.g., MX selection)
64264562Sgshapiro		**  are not "really" random.
64364562Sgshapiro		*/
64466494Sgshapiro# if STARTTLS
64566494Sgshapiro		seed = get_random();
64666494Sgshapiro		RAND_seed((void *) &last_disk_space_check,
64766494Sgshapiro			sizeof last_disk_space_check);
64866494Sgshapiro		RAND_seed((void *) &timenow, sizeof timenow);
64966494Sgshapiro		RAND_seed((void *) &seed, sizeof seed);
65066494Sgshapiro# else /* STARTTLS */
65164562Sgshapiro		(void) get_random();
65266494Sgshapiro# endif /* STARTTLS */
65364562Sgshapiro
65471345Sgshapiro#ifndef DEBUG_NO_FORK
65564562Sgshapiro		/*
65638032Speter		**  Create a pipe to keep the child from writing to the
65738032Speter		**  socket until after the parent has closed it.  Otherwise
65838032Speter		**  the parent may hang if the child has closed it first.
65938032Speter		*/
66038032Speter
66138032Speter		if (pipe(pipefd) < 0)
66238032Speter			pipefd[0] = pipefd[1] = -1;
66338032Speter
66464562Sgshapiro		(void) blocksignal(SIGCHLD);
66538032Speter		pid = fork();
66638032Speter		if (pid < 0)
66738032Speter		{
66838032Speter			syserr("daemon: cannot fork");
66938032Speter			if (pipefd[0] != -1)
67038032Speter			{
67138032Speter				(void) close(pipefd[0]);
67238032Speter				(void) close(pipefd[1]);
67338032Speter			}
67438032Speter			(void) releasesignal(SIGCHLD);
67564562Sgshapiro			(void) sleep(10);
67638032Speter			(void) close(t);
67738032Speter			continue;
67838032Speter		}
67971345Sgshapiro#else /* ! DEBUG_NO_FORK */
68071345Sgshapiro		pid = 0;
68171345Sgshapiro#endif /* ! DEBUG_NO_FORK */
68238032Speter
68338032Speter		if (pid == 0)
68438032Speter		{
68538032Speter			char *p;
68664562Sgshapiro			FILE *inchannel, *outchannel = NULL;
68738032Speter
68838032Speter			/*
68938032Speter			**  CHILD -- return to caller.
69038032Speter			**	Collect verified idea of sending host.
69138032Speter			**	Verify calling user id if possible here.
69238032Speter			*/
69338032Speter
69477349Sgshapiro			/* Reset global flags */
69577349Sgshapiro			RestartRequest = NULL;
69677349Sgshapiro			ShutdownRequest = NULL;
69777349Sgshapiro			PendingSignal = 0;
69877349Sgshapiro
69977349Sgshapiro			(void) releasesignal(SIGALRM);
70077349Sgshapiro			(void) releasesignal(SIGCHLD);
70177349Sgshapiro			(void) setsignal(SIGCHLD, SIG_DFL);
70277349Sgshapiro			(void) setsignal(SIGHUP, SIG_DFL);
70377349Sgshapiro			(void) setsignal(SIGTERM, intsig);
70477349Sgshapiro
70564562Sgshapiro			if (!control)
70664562Sgshapiro			{
70764562Sgshapiro				define(macid("{daemon_addr}", NULL),
70864562Sgshapiro				       newstr(anynet_ntoa(&Daemons[curdaemon].d_addr)),
70964562Sgshapiro				       &BlankEnvelope);
71064562Sgshapiro				(void) snprintf(status, sizeof status, "%d",
71164562Sgshapiro						ntohs(Daemons[curdaemon].d_port));
71264562Sgshapiro				define(macid("{daemon_port}", NULL),
71364562Sgshapiro				       newstr(status), &BlankEnvelope);
71464562Sgshapiro			}
71564562Sgshapiro
71664562Sgshapiro			for (idx = 0; idx < ndaemons; idx++)
71764562Sgshapiro			{
71864562Sgshapiro				if (Daemons[idx].d_socket >= 0)
71964562Sgshapiro					(void) close(Daemons[idx].d_socket);
72080785Sgshapiro				Daemons[idx].d_socket = -1;
72164562Sgshapiro			}
72242575Speter			clrcontrol();
72338032Speter
72464562Sgshapiro			/* Avoid SMTP daemon actions if control command */
72564562Sgshapiro			if (control)
72664562Sgshapiro			{
72764562Sgshapiro				/* Add control socket process */
72864562Sgshapiro				proc_list_add(getpid(), "console socket child",
72964562Sgshapiro					PROC_CONTROL_CHILD);
73064562Sgshapiro			}
73164562Sgshapiro			else
73264562Sgshapiro			{
73364562Sgshapiro				proc_list_clear();
73442575Speter
73564562Sgshapiro				/* Add parent process as first child item */
73664562Sgshapiro				proc_list_add(getpid(), "daemon child",
73764562Sgshapiro					      PROC_DAEMON_CHILD);
73838032Speter
73964562Sgshapiro				/* don't schedule queue runs if ETRN */
74064562Sgshapiro				QueueIntvl = 0;
74138032Speter
74264562Sgshapiro				sm_setproctitle(TRUE, e, "startup with %s",
74364562Sgshapiro						anynet_ntoa(&RealHostAddr));
74464562Sgshapiro			}
74564562Sgshapiro
74671345Sgshapiro#ifndef DEBUG_NO_FORK
74738032Speter			if (pipefd[0] != -1)
74838032Speter			{
74938032Speter				auto char c;
75038032Speter
75138032Speter				/*
75238032Speter				**  Wait for the parent to close the write end
75338032Speter				**  of the pipe, which we will see as an EOF.
75438032Speter				**  This guarantees that we won't write to the
75538032Speter				**  socket until after the parent has closed
75638032Speter				**  the pipe.
75738032Speter				*/
75838032Speter
75938032Speter				/* close the write end of the pipe */
76038032Speter				(void) close(pipefd[1]);
76138032Speter
76238032Speter				/* we shouldn't be interrupted, but ... */
76338032Speter				while (read(pipefd[0], &c, 1) < 0 &&
76438032Speter				       errno == EINTR)
76538032Speter					continue;
76638032Speter				(void) close(pipefd[0]);
76738032Speter			}
76871345Sgshapiro#endif /* ! DEBUG_NO_FORK */
76938032Speter
77064562Sgshapiro			/* control socket processing */
77164562Sgshapiro			if (control)
77264562Sgshapiro			{
77364562Sgshapiro				control_command(t, e);
77464562Sgshapiro
77564562Sgshapiro				/* NOTREACHED */
77664562Sgshapiro				exit(EX_SOFTWARE);
77764562Sgshapiro			}
77864562Sgshapiro
77938032Speter			/* determine host name */
78038032Speter			p = hostnamebyanyaddr(&RealHostAddr);
78138032Speter			if (strlen(p) > (SIZE_T) MAXNAME)
78238032Speter				p[MAXNAME] = '\0';
78338032Speter			RealHostName = newstr(p);
78464562Sgshapiro			if (RealHostName[0] == '[')
78564562Sgshapiro			{
78664562Sgshapiro				/* TEMP, FAIL: which one? */
78764562Sgshapiro				define(macid("{client_resolve}", NULL),
78864562Sgshapiro				       (h_errno == TRY_AGAIN) ? "TEMP" : "FAIL",
78964562Sgshapiro				       &BlankEnvelope);
79064562Sgshapiro			}
79164562Sgshapiro			else
79264562Sgshapiro				define(macid("{client_resolve}", NULL), "OK",
79364562Sgshapiro				       &BlankEnvelope);
79464562Sgshapiro			sm_setproctitle(TRUE, e, "startup with %s", p);
79538032Speter
79638032Speter			if ((inchannel = fdopen(t, "r")) == NULL ||
79738032Speter			    (t = dup(t)) < 0 ||
79838032Speter			    (outchannel = fdopen(t, "w")) == NULL)
79938032Speter			{
80038032Speter				syserr("cannot open SMTP server channel, fd=%d", t);
80142575Speter				finis(FALSE, EX_OK);
80238032Speter			}
80338032Speter
80438032Speter			InChannel = inchannel;
80538032Speter			OutChannel = outchannel;
80638032Speter			DisConnected = FALSE;
80738032Speter
80864562Sgshapiro# ifdef XLA
80938032Speter			if (!xla_host_ok(RealHostName))
81038032Speter			{
81164562Sgshapiro				message("421 4.4.5 Too many SMTP sessions for this host");
81242575Speter				finis(FALSE, EX_OK);
81338032Speter			}
81464562Sgshapiro# endif /* XLA */
81564562Sgshapiro			/* find out name for interface of connection */
81664562Sgshapiro			if (getsockname(fileno(InChannel), &sa.sa,
81764562Sgshapiro					&len) == 0)
81864562Sgshapiro			{
81964562Sgshapiro				p = hostnamebyanyaddr(&sa);
82064562Sgshapiro				if (tTd(15, 9))
82164562Sgshapiro					dprintf("getreq: got name %s\n", p);
82264562Sgshapiro				define(macid("{if_name}", NULL),
82364562Sgshapiro				       newstr(p), &BlankEnvelope);
82464562Sgshapiro
82564562Sgshapiro				/* do this only if it is not the loopback */
82664562Sgshapiro				/* interface: how to figure out? XXX */
82764562Sgshapiro				if (!isloopback(sa))
82864562Sgshapiro				{
82964562Sgshapiro					define(macid("{if_addr}", NULL),
83064562Sgshapiro					       newstr(anynet_ntoa(&sa)),
83164562Sgshapiro					       &BlankEnvelope);
83264562Sgshapiro					p = xalloc(5);
83364562Sgshapiro					snprintf(p, 4, "%d", sa.sa.sa_family);
83464562Sgshapiro					define(macid("{if_family}", NULL), p,
83564562Sgshapiro					       &BlankEnvelope);
83664562Sgshapiro					if (tTd(15, 7))
83764562Sgshapiro						dprintf("getreq: got addr %s and family %s\n",
83864562Sgshapiro							macvalue(macid("{if_addr}", NULL),
83964562Sgshapiro								 &BlankEnvelope),
84064562Sgshapiro							macvalue(macid("{if_addr}", NULL),
84164562Sgshapiro								 &BlankEnvelope));
84264562Sgshapiro				}
84364562Sgshapiro				else
84464562Sgshapiro				{
84564562Sgshapiro					define(macid("{if_addr}", NULL), NULL,
84664562Sgshapiro					       &BlankEnvelope);
84764562Sgshapiro					define(macid("{if_family}", NULL), NULL,
84864562Sgshapiro					       &BlankEnvelope);
84964562Sgshapiro				}
85064562Sgshapiro			}
85164562Sgshapiro			else
85264562Sgshapiro			{
85364562Sgshapiro				if (tTd(15, 7))
85464562Sgshapiro					dprintf("getreq: getsockname failed\n");
85564562Sgshapiro				define(macid("{if_name}", NULL), NULL,
85664562Sgshapiro				       &BlankEnvelope);
85764562Sgshapiro				define(macid("{if_addr}", NULL), NULL,
85864562Sgshapiro				       &BlankEnvelope);
85964562Sgshapiro				define(macid("{if_family}", NULL), NULL,
86064562Sgshapiro				       &BlankEnvelope);
86164562Sgshapiro			}
86238032Speter			break;
86338032Speter		}
86438032Speter
86538032Speter		/* parent -- keep track of children */
86664562Sgshapiro		if (control)
86764562Sgshapiro		{
86864562Sgshapiro			snprintf(status, sizeof status, "control socket server child");
86964562Sgshapiro			proc_list_add(pid, status, PROC_CONTROL);
87064562Sgshapiro		}
87164562Sgshapiro		else
87264562Sgshapiro		{
87364562Sgshapiro			snprintf(status, sizeof status,
87464562Sgshapiro				 "SMTP server child for %s",
87564562Sgshapiro				 anynet_ntoa(&RealHostAddr));
87664562Sgshapiro			proc_list_add(pid, status, PROC_DAEMON);
87764562Sgshapiro		}
87838032Speter		(void) releasesignal(SIGCHLD);
87938032Speter
88038032Speter		/* close the read end of the synchronization pipe */
88138032Speter		if (pipefd[0] != -1)
88264562Sgshapiro		{
88338032Speter			(void) close(pipefd[0]);
88464562Sgshapiro			pipefd[0] = -1;
88564562Sgshapiro		}
88638032Speter
88738032Speter		/* close the port so that others will hang (for a while) */
88838032Speter		(void) close(t);
88938032Speter
89038032Speter		/* release the child by closing the read end of the sync pipe */
89138032Speter		if (pipefd[1] != -1)
89264562Sgshapiro		{
89338032Speter			(void) close(pipefd[1]);
89464562Sgshapiro			pipefd[1] = -1;
89564562Sgshapiro		}
89638032Speter	}
89764562Sgshapiro
89838032Speter	if (tTd(15, 2))
89964562Sgshapiro		dprintf("getreq: returning\n");
90064562Sgshapiro	return &Daemons[curdaemon].d_flags;
90138032Speter}
90238032Speter/*
90364562Sgshapiro**  OPENDAEMONSOCKET -- open SMTP socket
90438032Speter**
90564562Sgshapiro**	Deals with setting all appropriate options.
90638032Speter**
90738032Speter**	Parameters:
90864562Sgshapiro**		d -- the structure for the daemon to open.
90938032Speter**		firsttime -- set if this is the initial open.
91038032Speter**
91138032Speter**	Returns:
91238032Speter**		Size in bytes of the daemon socket addr.
91338032Speter**
91438032Speter**	Side Effects:
91538032Speter**		Leaves DaemonSocket set to the open socket.
91638032Speter**		Exits if the socket cannot be created.
91738032Speter*/
91838032Speter
91964562Sgshapiro# define MAXOPENTRIES	10	/* maximum number of tries to open connection */
92038032Speter
92164562Sgshapirostatic int
92264562Sgshapiroopendaemonsocket(d, firsttime)
92364562Sgshapiro	struct daemon *d;
92438032Speter	bool firsttime;
92538032Speter{
92638032Speter	int on = 1;
92764562Sgshapiro	int fdflags;
92864562Sgshapiro	SOCKADDR_LEN_T socksize = 0;
92938032Speter	int ntries = 0;
93064562Sgshapiro	int save_errno;
93138032Speter
93238032Speter	if (tTd(15, 2))
93364562Sgshapiro		dprintf("opendaemonsocket(%s)\n", d->d_name);
93438032Speter
93538032Speter	do
93638032Speter	{
93738032Speter		if (ntries > 0)
93864562Sgshapiro			(void) sleep(5);
93964562Sgshapiro		if (firsttime || d->d_socket < 0)
94038032Speter		{
94164562Sgshapiro			d->d_socket = socket(d->d_addr.sa.sa_family,
94264562Sgshapiro					     SOCK_STREAM, 0);
94364562Sgshapiro			if (d->d_socket < 0)
94438032Speter			{
94564562Sgshapiro				save_errno = errno;
94664562Sgshapiro				syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name);
94738032Speter			  severe:
94838032Speter				if (LogLevel > 0)
94938032Speter					sm_syslog(LOG_ALERT, NOQID,
95064562Sgshapiro						  "daemon %s: problem creating SMTP socket", d->d_name);
95164562Sgshapiro				d->d_socket = -1;
95238032Speter				continue;
95338032Speter			}
95438032Speter
95538032Speter			/* turn on network debugging? */
95638032Speter			if (tTd(15, 101))
95764562Sgshapiro				(void) setsockopt(d->d_socket, SOL_SOCKET,
95838032Speter						  SO_DEBUG, (char *)&on,
95938032Speter						  sizeof on);
96038032Speter
96164562Sgshapiro			(void) setsockopt(d->d_socket, SOL_SOCKET,
96238032Speter					  SO_REUSEADDR, (char *)&on, sizeof on);
96364562Sgshapiro			(void) setsockopt(d->d_socket, SOL_SOCKET,
96438032Speter					  SO_KEEPALIVE, (char *)&on, sizeof on);
96538032Speter
96664562Sgshapiro# ifdef SO_RCVBUF
96764562Sgshapiro			if (d->d_tcprcvbufsize > 0)
96838032Speter			{
96964562Sgshapiro				if (setsockopt(d->d_socket, SOL_SOCKET,
97038032Speter					       SO_RCVBUF,
97164562Sgshapiro					       (char *) &d->d_tcprcvbufsize,
97264562Sgshapiro					       sizeof(d->d_tcprcvbufsize)) < 0)
97364562Sgshapiro					syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
97438032Speter			}
97564562Sgshapiro# endif /* SO_RCVBUF */
97664562Sgshapiro# ifdef SO_SNDBUF
97764562Sgshapiro			if (d->d_tcpsndbufsize > 0)
97864562Sgshapiro			{
97964562Sgshapiro				if (setsockopt(d->d_socket, SOL_SOCKET,
98064562Sgshapiro					       SO_SNDBUF,
98164562Sgshapiro					       (char *) &d->d_tcpsndbufsize,
98264562Sgshapiro					       sizeof(d->d_tcpsndbufsize)) < 0)
98364562Sgshapiro					syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
98464562Sgshapiro			}
98564562Sgshapiro# endif /* SO_SNDBUF */
98638032Speter
98764562Sgshapiro			if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
98864562Sgshapiro			    fcntl(d->d_socket, F_SETFD,
98964562Sgshapiro				  fdflags | FD_CLOEXEC) == -1)
99038032Speter			{
99164562Sgshapiro				save_errno = errno;
99264562Sgshapiro				syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
99364562Sgshapiro				       d->d_name,
99464562Sgshapiro				       fdflags == -1 ? "get" : "set",
99564562Sgshapiro				       errstring(save_errno));
99664562Sgshapiro				(void) close(d->d_socket);
99764562Sgshapiro				goto severe;
99864562Sgshapiro			}
99964562Sgshapiro
100064562Sgshapiro			switch (d->d_addr.sa.sa_family)
100164562Sgshapiro			{
100238032Speter# if NETINET
100338032Speter			  case AF_INET:
100464562Sgshapiro				socksize = sizeof d->d_addr.sin;
100538032Speter				break;
100664562Sgshapiro# endif /* NETINET */
100738032Speter
100864562Sgshapiro# if NETINET6
100964562Sgshapiro			  case AF_INET6:
101064562Sgshapiro				socksize = sizeof d->d_addr.sin6;
101164562Sgshapiro				break;
101264562Sgshapiro# endif /* NETINET6 */
101364562Sgshapiro
101438032Speter# if NETISO
101538032Speter			  case AF_ISO:
101664562Sgshapiro				socksize = sizeof d->d_addr.siso;
101738032Speter				break;
101864562Sgshapiro# endif /* NETISO */
101938032Speter
102038032Speter			  default:
102164562Sgshapiro				socksize = sizeof d->d_addr;
102238032Speter				break;
102338032Speter			}
102438032Speter
102564562Sgshapiro			if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
102638032Speter			{
102738032Speter				/* probably another daemon already */
102864562Sgshapiro				save_errno = errno;
102964562Sgshapiro				syserr("opendaemonsocket: daemon %s: cannot bind",
103064562Sgshapiro				       d->d_name);
103164562Sgshapiro				(void) close(d->d_socket);
103238032Speter				goto severe;
103338032Speter			}
103438032Speter		}
103564562Sgshapiro		if (!firsttime &&
103664562Sgshapiro		    listen(d->d_socket, d->d_listenqueue) < 0)
103738032Speter		{
103864562Sgshapiro			save_errno = errno;
103964562Sgshapiro			syserr("opendaemonsocket: daemon %s: cannot listen",
104064562Sgshapiro			       d->d_name);
104164562Sgshapiro			(void) close(d->d_socket);
104238032Speter			goto severe;
104338032Speter		}
104438032Speter		return socksize;
104564562Sgshapiro	} while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
104664562Sgshapiro	syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
104764562Sgshapiro	       d->d_name);
104864562Sgshapiro	/* NOTREACHED */
104938032Speter	return -1;  /* avoid compiler warning on IRIX */
105038032Speter}
105138032Speter/*
105264562Sgshapiro**  SETUPDAEMON -- setup socket for daemon
105364562Sgshapiro**
105464562Sgshapiro**	Parameters:
105564562Sgshapiro**		daemonaddr -- socket for daemon
105664562Sgshapiro**		daemon -- number of daemon
105764562Sgshapiro**
105864562Sgshapiro**	Returns:
105964562Sgshapiro**		port number on which daemon should run
106064562Sgshapiro**
106164562Sgshapiro*/
106264562Sgshapirostatic u_short
106364562Sgshapirosetupdaemon(daemonaddr)
106464562Sgshapiro	SOCKADDR *daemonaddr;
106564562Sgshapiro{
106664562Sgshapiro	u_short port;
106764562Sgshapiro
106864562Sgshapiro	/*
106964562Sgshapiro	**  Set up the address for the mailer.
107064562Sgshapiro	*/
107164562Sgshapiro
107264562Sgshapiro	if (daemonaddr->sa.sa_family == AF_UNSPEC)
107364562Sgshapiro	{
107464562Sgshapiro		memset(daemonaddr, '\0', sizeof *daemonaddr);
107564562Sgshapiro# if NETINET
107664562Sgshapiro		daemonaddr->sa.sa_family = AF_INET;
107764562Sgshapiro# endif /* NETINET */
107864562Sgshapiro	}
107964562Sgshapiro
108064562Sgshapiro	switch (daemonaddr->sa.sa_family)
108164562Sgshapiro	{
108264562Sgshapiro# if NETINET
108364562Sgshapiro	  case AF_INET:
108464562Sgshapiro		if (daemonaddr->sin.sin_addr.s_addr == 0)
108564562Sgshapiro			daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
108664562Sgshapiro		port = daemonaddr->sin.sin_port;
108764562Sgshapiro		break;
108864562Sgshapiro# endif /* NETINET */
108964562Sgshapiro
109064562Sgshapiro# if NETINET6
109164562Sgshapiro	  case AF_INET6:
109264562Sgshapiro		if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
109364562Sgshapiro			daemonaddr->sin6.sin6_addr = in6addr_any;
109464562Sgshapiro		port = daemonaddr->sin6.sin6_port;
109564562Sgshapiro		break;
109664562Sgshapiro# endif /* NETINET6 */
109764562Sgshapiro
109864562Sgshapiro	  default:
109964562Sgshapiro		/* unknown protocol */
110064562Sgshapiro		port = 0;
110164562Sgshapiro		break;
110264562Sgshapiro	}
110364562Sgshapiro	if (port == 0)
110464562Sgshapiro	{
110564562Sgshapiro# ifdef NO_GETSERVBYNAME
110664562Sgshapiro		port = htons(25);
110764562Sgshapiro# else /* NO_GETSERVBYNAME */
110864562Sgshapiro		{
110964562Sgshapiro			register struct servent *sp;
111064562Sgshapiro
111164562Sgshapiro			sp = getservbyname("smtp", "tcp");
111264562Sgshapiro			if (sp == NULL)
111364562Sgshapiro			{
111464562Sgshapiro				syserr("554 5.3.5 service \"smtp\" unknown");
111564562Sgshapiro				port = htons(25);
111664562Sgshapiro			}
111764562Sgshapiro			else
111864562Sgshapiro				port = sp->s_port;
111964562Sgshapiro		}
112064562Sgshapiro# endif /* NO_GETSERVBYNAME */
112164562Sgshapiro	}
112264562Sgshapiro
112364562Sgshapiro	switch (daemonaddr->sa.sa_family)
112464562Sgshapiro	{
112564562Sgshapiro# if NETINET
112664562Sgshapiro	  case AF_INET:
112764562Sgshapiro		daemonaddr->sin.sin_port = port;
112864562Sgshapiro		break;
112964562Sgshapiro# endif /* NETINET */
113064562Sgshapiro
113164562Sgshapiro# if NETINET6
113264562Sgshapiro	  case AF_INET6:
113364562Sgshapiro		daemonaddr->sin6.sin6_port = port;
113464562Sgshapiro		break;
113564562Sgshapiro# endif /* NETINET6 */
113664562Sgshapiro
113764562Sgshapiro	  default:
113864562Sgshapiro		/* unknown protocol */
113964562Sgshapiro		break;
114064562Sgshapiro	}
114164562Sgshapiro	return(port);
114264562Sgshapiro}
114364562Sgshapiro/*
114438032Speter**  CLRDAEMON -- reset the daemon connection
114538032Speter**
114638032Speter**	Parameters:
114738032Speter**		none.
114838032Speter**
114938032Speter**	Returns:
115038032Speter**		none.
115138032Speter**
115238032Speter**	Side Effects:
115338032Speter**		releases any resources used by the passive daemon.
115438032Speter*/
115538032Speter
115638032Spetervoid
115738032Speterclrdaemon()
115838032Speter{
115964562Sgshapiro	int i;
116064562Sgshapiro
116164562Sgshapiro	for (i = 0; i < ndaemons; i++)
116264562Sgshapiro	{
116364562Sgshapiro		if (Daemons[i].d_socket >= 0)
116464562Sgshapiro			(void) close(Daemons[i].d_socket);
116564562Sgshapiro		Daemons[i].d_socket = -1;
116664562Sgshapiro	}
116738032Speter}
116838032Speter/*
116964562Sgshapiro**  SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
117038032Speter**
117138032Speter**	Parameters:
117238032Speter**		p -- the options line.
117364562Sgshapiro**		d -- the daemon structure to fill in.
117438032Speter**
117538032Speter**	Returns:
117638032Speter**		none.
117738032Speter*/
117838032Speter
117964562Sgshapirostatic void
118064562Sgshapirosetsockaddroptions(p, d)
118138032Speter	register char *p;
118264562Sgshapiro	struct daemon *d;
118338032Speter{
118464562Sgshapiro# if NETISO
118571345Sgshapiro	short portno;
118664562Sgshapiro# endif /* NETISO */
118764562Sgshapiro	int l;
118864562Sgshapiro	char *h, *flags;
118971345Sgshapiro	char *port = NULL;
119071345Sgshapiro	char *addr = NULL;
119138032Speter
119264562Sgshapiro# if NETINET
119364562Sgshapiro	if (d->d_addr.sa.sa_family == AF_UNSPEC)
119464562Sgshapiro		d->d_addr.sa.sa_family = AF_INET;
119564562Sgshapiro# endif /* NETINET */
119664562Sgshapiro
119738032Speter	while (p != NULL)
119838032Speter	{
119938032Speter		register char *f;
120038032Speter		register char *v;
120138032Speter
120238032Speter		while (isascii(*p) && isspace(*p))
120338032Speter			p++;
120438032Speter		if (*p == '\0')
120538032Speter			break;
120638032Speter		f = p;
120738032Speter		p = strchr(p, ',');
120838032Speter		if (p != NULL)
120938032Speter			*p++ = '\0';
121038032Speter		v = strchr(f, '=');
121138032Speter		if (v == NULL)
121238032Speter			continue;
121338032Speter		while (isascii(*++v) && isspace(*v))
121438032Speter			continue;
121538032Speter		if (isascii(*f) && islower(*f))
121638032Speter			*f = toupper(*f);
121738032Speter
121838032Speter		switch (*f)
121938032Speter		{
122038032Speter		  case 'F':		/* address family */
122138032Speter			if (isascii(*v) && isdigit(*v))
122264562Sgshapiro				d->d_addr.sa.sa_family = atoi(v);
122364562Sgshapiro# if NETINET
122438032Speter			else if (strcasecmp(v, "inet") == 0)
122564562Sgshapiro				d->d_addr.sa.sa_family = AF_INET;
122664562Sgshapiro# endif /* NETINET */
122764562Sgshapiro# if NETINET6
122864562Sgshapiro			else if (strcasecmp(v, "inet6") == 0)
122964562Sgshapiro				d->d_addr.sa.sa_family = AF_INET6;
123064562Sgshapiro# endif /* NETINET6 */
123164562Sgshapiro# if NETISO
123238032Speter			else if (strcasecmp(v, "iso") == 0)
123364562Sgshapiro				d->d_addr.sa.sa_family = AF_ISO;
123464562Sgshapiro# endif /* NETISO */
123564562Sgshapiro# if NETNS
123638032Speter			else if (strcasecmp(v, "ns") == 0)
123764562Sgshapiro				d->d_addr.sa.sa_family = AF_NS;
123864562Sgshapiro# endif /* NETNS */
123964562Sgshapiro# if NETX25
124038032Speter			else if (strcasecmp(v, "x.25") == 0)
124164562Sgshapiro				d->d_addr.sa.sa_family = AF_CCITT;
124264562Sgshapiro# endif /* NETX25 */
124338032Speter			else
124464562Sgshapiro				syserr("554 5.3.5 Unknown address family %s in Family=option",
124564562Sgshapiro				       v);
124638032Speter			break;
124738032Speter
124838032Speter		  case 'A':		/* address */
124971345Sgshapiro			addr = v;
125038032Speter			break;
125138032Speter
125238032Speter		  case 'P':		/* port */
125371345Sgshapiro			port = v;
125438032Speter			break;
125538032Speter
125638032Speter		  case 'L':		/* listen queue size */
125764562Sgshapiro			d->d_listenqueue = atoi(v);
125838032Speter			break;
125938032Speter
126064562Sgshapiro		  case 'M':		/* modifiers (flags) */
126164562Sgshapiro			l = 3 * strlen(v) + 3;
126264562Sgshapiro			h = v;
126364562Sgshapiro			flags = xalloc(l);
126464562Sgshapiro			d->d_mflags = flags;
126564562Sgshapiro			for (; *h != '\0'; h++)
126664562Sgshapiro			{
126764562Sgshapiro				if (!(isascii(*h) && isspace(*h)))
126864562Sgshapiro				{
126964562Sgshapiro					if (flags != d->d_mflags)
127066494Sgshapiro						*flags++ = ' ';
127164562Sgshapiro					*flags++ = *h;
127264562Sgshapiro					if (isupper(*h))
127364562Sgshapiro						*flags++ = *h;
127464562Sgshapiro				}
127564562Sgshapiro			}
127664562Sgshapiro			*flags++ = '\0';
127764562Sgshapiro			for (; *v != '\0'; v++)
127864562Sgshapiro				if (!(isascii(*v) && isspace(*v)))
127971345Sgshapiro					setbitn(bitidx(*v), d->d_flags);
128064562Sgshapiro			break;
128164562Sgshapiro
128238032Speter		  case 'S':		/* send buffer size */
128364562Sgshapiro			d->d_tcpsndbufsize = atoi(v);
128438032Speter			break;
128538032Speter
128638032Speter		  case 'R':		/* receive buffer size */
128764562Sgshapiro			d->d_tcprcvbufsize = atoi(v);
128838032Speter			break;
128938032Speter
129064562Sgshapiro		  case 'N':		/* name */
129164562Sgshapiro			d->d_name = v;
129264562Sgshapiro			break;
129364562Sgshapiro
129438032Speter		  default:
129564562Sgshapiro			syserr("554 5.3.5 PortOptions parameter \"%s\" unknown",
129664562Sgshapiro			       f);
129738032Speter		}
129838032Speter	}
129971345Sgshapiro
130071345Sgshapiro	/* Check addr and port after finding family */
130171345Sgshapiro	if (addr != NULL)
130271345Sgshapiro	{
130371345Sgshapiro		switch (d->d_addr.sa.sa_family)
130471345Sgshapiro		{
130571345Sgshapiro# if NETINET
130671345Sgshapiro		  case AF_INET:
130771345Sgshapiro			if (!isascii(*addr) || !isdigit(*addr) ||
130871345Sgshapiro			    ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE))
130971345Sgshapiro			{
131071345Sgshapiro				register struct hostent *hp;
131171345Sgshapiro
131271345Sgshapiro				hp = sm_gethostbyname(addr, AF_INET);
131371345Sgshapiro				if (hp == NULL)
131471345Sgshapiro					syserr("554 5.3.0 host \"%s\" unknown",
131571345Sgshapiro					       addr);
131671345Sgshapiro				else
131771345Sgshapiro				{
131871345Sgshapiro					while (*(hp->h_addr_list) != NULL &&
131971345Sgshapiro					       hp->h_addrtype != AF_INET)
132071345Sgshapiro						hp->h_addr_list++;
132171345Sgshapiro					if (*(hp->h_addr_list) == NULL)
132271345Sgshapiro						syserr("554 5.3.0 host \"%s\" unknown",
132371345Sgshapiro						       addr);
132471345Sgshapiro					else
132571345Sgshapiro						memmove(&d->d_addr.sin.sin_addr,
132671345Sgshapiro							*(hp->h_addr_list),
132771345Sgshapiro							INADDRSZ);
132871345Sgshapiro#  if _FFR_FREEHOSTENT && NETINET6
132971345Sgshapiro					freehostent(hp);
133071345Sgshapiro					hp = NULL;
133171345Sgshapiro#  endif /* _FFR_FREEHOSTENT && NETINET6 */
133271345Sgshapiro				}
133371345Sgshapiro			}
133471345Sgshapiro			break;
133571345Sgshapiro# endif /* NETINET */
133671345Sgshapiro
133771345Sgshapiro# if NETINET6
133871345Sgshapiro		  case AF_INET6:
133971345Sgshapiro			if (!isascii(*addr) ||
134071345Sgshapiro			    (!isxdigit(*addr) && *addr != ':') ||
134171345Sgshapiro			    inet_pton(AF_INET6, addr,
134271345Sgshapiro				      &d->d_addr.sin6.sin6_addr) != 1)
134371345Sgshapiro			{
134471345Sgshapiro				register struct hostent *hp;
134571345Sgshapiro
134671345Sgshapiro				hp = sm_gethostbyname(addr, AF_INET6);
134771345Sgshapiro				if (hp == NULL)
134871345Sgshapiro					syserr("554 5.3.0 host \"%s\" unknown",
134971345Sgshapiro					       addr);
135071345Sgshapiro				else
135171345Sgshapiro				{
135271345Sgshapiro					while (*(hp->h_addr_list) != NULL &&
135371345Sgshapiro					       hp->h_addrtype != AF_INET6)
135471345Sgshapiro						hp->h_addr_list++;
135571345Sgshapiro					if (*(hp->h_addr_list) == NULL)
135671345Sgshapiro						syserr("554 5.3.0 host \"%s\" unknown",
135771345Sgshapiro						       addr);
135871345Sgshapiro					else
135971345Sgshapiro						memmove(&d->d_addr.sin6.sin6_addr,
136071345Sgshapiro							*(hp->h_addr_list),
136171345Sgshapiro							IN6ADDRSZ);
136271345Sgshapiro#  if _FFR_FREEHOSTENT
136371345Sgshapiro					freehostent(hp);
136471345Sgshapiro					hp = NULL;
136571345Sgshapiro#  endif /* _FFR_FREEHOSTENT */
136671345Sgshapiro				}
136771345Sgshapiro			}
136871345Sgshapiro			break;
136971345Sgshapiro# endif /* NETINET6 */
137071345Sgshapiro
137171345Sgshapiro		  default:
137271345Sgshapiro			syserr("554 5.3.5 address= option unsupported for family %d",
137371345Sgshapiro			       d->d_addr.sa.sa_family);
137471345Sgshapiro			break;
137571345Sgshapiro		}
137671345Sgshapiro	}
137771345Sgshapiro
137871345Sgshapiro	if (port != NULL)
137971345Sgshapiro	{
138071345Sgshapiro		switch (d->d_addr.sa.sa_family)
138171345Sgshapiro		{
138271345Sgshapiro# if NETINET
138371345Sgshapiro		  case AF_INET:
138471345Sgshapiro			if (isascii(*port) && isdigit(*port))
138571345Sgshapiro				d->d_addr.sin.sin_port = htons((u_short)atoi((const char *)port));
138671345Sgshapiro			else
138771345Sgshapiro			{
138871345Sgshapiro#  ifdef NO_GETSERVBYNAME
138971345Sgshapiro				syserr("554 5.3.5 invalid port number: %s",
139071345Sgshapiro				       port);
139171345Sgshapiro#  else /* NO_GETSERVBYNAME */
139271345Sgshapiro				register struct servent *sp;
139371345Sgshapiro
139471345Sgshapiro				sp = getservbyname(port, "tcp");
139571345Sgshapiro				if (sp == NULL)
139671345Sgshapiro					syserr("554 5.3.5 service \"%s\" unknown",
139771345Sgshapiro					       port);
139871345Sgshapiro				else
139971345Sgshapiro					d->d_addr.sin.sin_port = sp->s_port;
140071345Sgshapiro#  endif /* NO_GETSERVBYNAME */
140171345Sgshapiro			}
140271345Sgshapiro			break;
140371345Sgshapiro# endif /* NETINET */
140471345Sgshapiro
140571345Sgshapiro# if NETINET6
140671345Sgshapiro		  case AF_INET6:
140771345Sgshapiro			if (isascii(*port) && isdigit(*port))
140871345Sgshapiro				d->d_addr.sin6.sin6_port = htons((u_short)atoi(port));
140971345Sgshapiro			else
141071345Sgshapiro			{
141171345Sgshapiro#  ifdef NO_GETSERVBYNAME
141271345Sgshapiro				syserr("554 5.3.5 invalid port number: %s",
141371345Sgshapiro				       port);
141471345Sgshapiro#  else /* NO_GETSERVBYNAME */
141571345Sgshapiro				register struct servent *sp;
141671345Sgshapiro
141771345Sgshapiro				sp = getservbyname(port, "tcp");
141871345Sgshapiro				if (sp == NULL)
141971345Sgshapiro					syserr("554 5.3.5 service \"%s\" unknown",
142071345Sgshapiro					       port);
142171345Sgshapiro				else
142271345Sgshapiro					d->d_addr.sin6.sin6_port = sp->s_port;
142371345Sgshapiro#  endif /* NO_GETSERVBYNAME */
142471345Sgshapiro			}
142571345Sgshapiro			break;
142671345Sgshapiro# endif /* NETINET6 */
142771345Sgshapiro
142871345Sgshapiro# if NETISO
142971345Sgshapiro		  case AF_ISO:
143071345Sgshapiro			/* assume two byte transport selector */
143171345Sgshapiro			if (isascii(*port) && isdigit(*port))
143271345Sgshapiro				portno = htons((u_short)atoi(port));
143371345Sgshapiro			else
143471345Sgshapiro			{
143571345Sgshapiro#  ifdef NO_GETSERVBYNAME
143671345Sgshapiro				syserr("554 5.3.5 invalid port number: %s",
143771345Sgshapiro				       port);
143871345Sgshapiro#  else /* NO_GETSERVBYNAME */
143971345Sgshapiro				register struct servent *sp;
144071345Sgshapiro
144171345Sgshapiro				sp = getservbyname(port, "tcp");
144271345Sgshapiro				if (sp == NULL)
144371345Sgshapiro					syserr("554 5.3.5 service \"%s\" unknown",
144471345Sgshapiro					       port);
144571345Sgshapiro				else
144671345Sgshapiro					portno = sp->s_port;
144771345Sgshapiro#  endif /* NO_GETSERVBYNAME */
144871345Sgshapiro			}
144971345Sgshapiro			memmove(TSEL(&d->d_addr.siso),
145071345Sgshapiro				(char *) &portno, 2);
145171345Sgshapiro			break;
145271345Sgshapiro# endif /* NETISO */
145371345Sgshapiro
145471345Sgshapiro		  default:
145571345Sgshapiro			syserr("554 5.3.5 Port= option unsupported for family %d",
145671345Sgshapiro			       d->d_addr.sa.sa_family);
145771345Sgshapiro			break;
145871345Sgshapiro		}
145971345Sgshapiro	}
146038032Speter}
146138032Speter/*
146264562Sgshapiro**  SETDAEMONOPTIONS -- set options for running the MTA daemon
146338032Speter**
146438032Speter**	Parameters:
146564562Sgshapiro**		p -- the options line.
146664562Sgshapiro**
146764562Sgshapiro**	Returns:
146864562Sgshapiro**		TRUE if successful, FALSE otherwise.
146964562Sgshapiro*/
147064562Sgshapiro
147164562Sgshapirobool
147264562Sgshapirosetdaemonoptions(p)
147364562Sgshapiro	register char *p;
147464562Sgshapiro{
147564562Sgshapiro	if (ndaemons >= MAXDAEMONS)
147664562Sgshapiro		return FALSE;
147764562Sgshapiro	Daemons[ndaemons].d_socket = -1;
147864562Sgshapiro	Daemons[ndaemons].d_listenqueue = 10;
147964562Sgshapiro	clrbitmap(Daemons[ndaemons].d_flags);
148064562Sgshapiro	setsockaddroptions(p, &Daemons[ndaemons]);
148164562Sgshapiro
148264562Sgshapiro	if (Daemons[ndaemons].d_name != NULL)
148364562Sgshapiro		Daemons[ndaemons].d_name = newstr(Daemons[ndaemons].d_name);
148464562Sgshapiro	else
148564562Sgshapiro	{
148664562Sgshapiro		char num[30];
148764562Sgshapiro
148864562Sgshapiro		snprintf(num, sizeof num, "Daemon%d", ndaemons);
148964562Sgshapiro		Daemons[ndaemons].d_name = newstr(num);
149064562Sgshapiro	}
149164562Sgshapiro
149264562Sgshapiro	if (tTd(37, 1))
149364562Sgshapiro	{
149464562Sgshapiro		dprintf("Daemon %s flags: ", Daemons[ndaemons].d_name);
149564562Sgshapiro		if (bitnset(D_ETRNONLY, Daemons[ndaemons].d_flags))
149664562Sgshapiro			dprintf("ETRNONLY ");
149764562Sgshapiro		if (bitnset(D_NOETRN, Daemons[ndaemons].d_flags))
149864562Sgshapiro			dprintf("NOETRN ");
149964562Sgshapiro		dprintf("\n");
150064562Sgshapiro	}
150164562Sgshapiro	++ndaemons;
150264562Sgshapiro	return TRUE;
150364562Sgshapiro}
150464562Sgshapiro/*
150564562Sgshapiro**  INITDAEMON -- initialize daemon if not yet done.
150664562Sgshapiro**
150764562Sgshapiro**	Parameters:
150864562Sgshapiro**		none
150964562Sgshapiro**
151064562Sgshapiro**	Returns:
151164562Sgshapiro**		none
151264562Sgshapiro**
151364562Sgshapiro**	Side Effects:
151464562Sgshapiro**		initializes structure for one daemon.
151564562Sgshapiro*/
151664562Sgshapirovoid
151764562Sgshapiroinitdaemon()
151864562Sgshapiro{
151964562Sgshapiro	if (ndaemons == 0)
152064562Sgshapiro	{
152164562Sgshapiro		Daemons[ndaemons].d_socket = -1;
152264562Sgshapiro		Daemons[ndaemons].d_listenqueue = 10;
152364562Sgshapiro		Daemons[ndaemons].d_name = "Daemon0";
152464562Sgshapiro		ndaemons = 1;
152564562Sgshapiro	}
152664562Sgshapiro}
152764562Sgshapiro/*
152864562Sgshapiro**  SETCLIENTOPTIONS -- set options for running the client
152964562Sgshapiro**
153064562Sgshapiro**	Parameters:
153164562Sgshapiro**		p -- the options line.
153264562Sgshapiro**
153364562Sgshapiro**	Returns:
153464562Sgshapiro**		none.
153564562Sgshapiro*/
153664562Sgshapiro
153764562Sgshapirostatic SOCKADDR	ClientAddr;		/* address for client */
153864562Sgshapiro
153964562Sgshapirovoid
154064562Sgshapirosetclientoptions(p)
154164562Sgshapiro	register char *p;
154264562Sgshapiro{
154364562Sgshapiro	struct daemon d;
154464562Sgshapiro	extern ENVELOPE BlankEnvelope;
154564562Sgshapiro
154664562Sgshapiro	memset(&d, '\0', sizeof d);
154764562Sgshapiro	setsockaddroptions(p, &d);
154864562Sgshapiro
154964562Sgshapiro	/* grab what we need */
155064562Sgshapiro	memcpy(&ClientAddr, &d.d_addr, sizeof ClientAddr);
155164562Sgshapiro	TcpSndBufferSize = d.d_tcpsndbufsize;
155264562Sgshapiro	TcpRcvBufferSize = d.d_tcprcvbufsize;
155364562Sgshapiro	if (d.d_mflags != NULL)
155464562Sgshapiro		define(macid("{client_flags}", NULL), d.d_mflags,
155564562Sgshapiro		       &BlankEnvelope);
155664562Sgshapiro	else
155764562Sgshapiro		define(macid("{client_flags}", NULL), "", &BlankEnvelope);
155864562Sgshapiro}
155964562Sgshapiro/*
156064562Sgshapiro**  ADDR_FAMILY -- determine address family from address
156164562Sgshapiro**
156264562Sgshapiro**	Parameters:
156364562Sgshapiro**		addr -- the string representation of the address
156464562Sgshapiro**
156564562Sgshapiro**	Returns:
156664562Sgshapiro**		AF_INET, AF_INET6 or AF_UNSPEC
156764562Sgshapiro**
156864562Sgshapiro**	Side Effects:
156964562Sgshapiro**		none.
157064562Sgshapiro*/
157164562Sgshapiro
157264562Sgshapirostatic int
157364562Sgshapiroaddr_family(addr)
157464562Sgshapiro	char *addr;
157564562Sgshapiro{
157664562Sgshapiro# if NETINET6
157764562Sgshapiro	SOCKADDR clt_addr;
157864562Sgshapiro# endif /* NETINET6 */
157964562Sgshapiro
158064562Sgshapiro# if NETINET
158164562Sgshapiro	if (inet_addr(addr) != INADDR_NONE)
158264562Sgshapiro	{
158364562Sgshapiro		if (tTd(16, 9))
158464562Sgshapiro			printf("addr_family(%s): INET\n", addr);
158564562Sgshapiro		return AF_INET;
158664562Sgshapiro	}
158764562Sgshapiro# endif /* NETINET */
158864562Sgshapiro# if NETINET6
158964562Sgshapiro	if (inet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
159064562Sgshapiro	{
159164562Sgshapiro		if (tTd(16, 9))
159264562Sgshapiro			printf("addr_family(%s): INET6\n", addr);
159364562Sgshapiro		return AF_INET6;
159464562Sgshapiro	}
159564562Sgshapiro# endif /* NETINET6 */
159664562Sgshapiro	if (tTd(16, 9))
159764562Sgshapiro		printf("addr_family(%s): UNSPEC\n", addr);
159864562Sgshapiro	return AF_UNSPEC;
159964562Sgshapiro}
160064562Sgshapiro/*
160164562Sgshapiro**  MAKECONNECTION -- make a connection to an SMTP socket on a machine.
160264562Sgshapiro**
160364562Sgshapiro**	Parameters:
160438032Speter**		host -- the name of the host.
160538032Speter**		port -- the port number to connect to.
160638032Speter**		mci -- a pointer to the mail connection information
160738032Speter**			structure to be filled in.
160838032Speter**		e -- the current envelope.
160938032Speter**
161038032Speter**	Returns:
161138032Speter**		An exit code telling whether the connection could be
161238032Speter**			made and if not why not.
161338032Speter**
161438032Speter**	Side Effects:
161538032Speter**		none.
161638032Speter*/
161738032Speter
161838032Speterstatic jmp_buf	CtxConnectTimeout;
161938032Speter
162038032SpeterSOCKADDR	CurHostAddr;		/* address of current host */
162138032Speter
162238032Speterint
162338032Spetermakeconnection(host, port, mci, e)
162438032Speter	char *host;
162564562Sgshapiro	volatile u_int port;
162638032Speter	register MCI *mci;
162738032Speter	ENVELOPE *e;
162838032Speter{
162938032Speter	register volatile int addrno = 0;
163038032Speter	register volatile int s;
163138032Speter	register struct hostent *volatile hp = (struct hostent *)NULL;
163238032Speter	SOCKADDR addr;
163364562Sgshapiro	SOCKADDR clt_addr;
163464562Sgshapiro	int save_errno = 0;
163564562Sgshapiro	volatile SOCKADDR_LEN_T addrlen;
163638032Speter	volatile bool firstconnect;
163738032Speter	EVENT *volatile ev = NULL;
163864562Sgshapiro# if NETINET6
163964562Sgshapiro	volatile bool v6found = FALSE;
164064562Sgshapiro# endif /* NETINET6 */
164164562Sgshapiro	volatile int family = InetMode;
164264562Sgshapiro	SOCKADDR_LEN_T len;
164364562Sgshapiro	volatile SOCKADDR_LEN_T socksize = 0;
164464562Sgshapiro	volatile bool clt_bind;
164564562Sgshapiro	BITMAP256 d_flags;
164664562Sgshapiro	char *p;
164764562Sgshapiro	extern ENVELOPE BlankEnvelope;
164838032Speter
164964562Sgshapiro	/* retranslate ${daemon_flags} into bitmap */
165064562Sgshapiro	clrbitmap(d_flags);
165164562Sgshapiro	if ((p = macvalue(macid("{daemon_flags}", NULL), e)) != NULL)
165264562Sgshapiro	{
165364562Sgshapiro		for (; *p != '\0'; p++)
165464562Sgshapiro		{
165564562Sgshapiro			if (!(isascii(*p) && isspace(*p)))
165671345Sgshapiro				setbitn(bitidx(*p), d_flags);
165764562Sgshapiro		}
165864562Sgshapiro	}
165964562Sgshapiro
166064562Sgshapiro	/* "add" ${client_flags} to bitmap */
166164562Sgshapiro	if ((p = macvalue(macid("{client_flags}", NULL), e)) != NULL)
166264562Sgshapiro	{
166364562Sgshapiro		for (; *p != '\0'; p++)
166464562Sgshapiro		{
166564562Sgshapiro			/* look for just this one flag */
166664562Sgshapiro			if (*p == D_IFNHELO)
166764562Sgshapiro			{
166871345Sgshapiro				setbitn(bitidx(*p), d_flags);
166964562Sgshapiro				break;
167064562Sgshapiro			}
167164562Sgshapiro		}
167264562Sgshapiro	}
167364562Sgshapiro
167464562Sgshapiro# if NETINET6
167564562Sgshapiro v4retry:
167664562Sgshapiro# endif /* NETINET6 */
167764562Sgshapiro	clt_bind = FALSE;
167864562Sgshapiro
167964562Sgshapiro	/* Set up the address for outgoing connection. */
168064562Sgshapiro	if (bitnset(D_BINDIF, d_flags) &&
168173188Sgshapiro	    (p = macvalue(macid("{if_addr}", NULL), e)) != NULL &&
168273188Sgshapiro	    *p != '\0')
168364562Sgshapiro	{
168464562Sgshapiro# if NETINET6
168564562Sgshapiro		char p6[INET6_ADDRSTRLEN];
168664562Sgshapiro# endif /* NETINET6 */
168764562Sgshapiro
168864562Sgshapiro		memset(&clt_addr, '\0', sizeof clt_addr);
168964562Sgshapiro
169064562Sgshapiro		/* infer the address family from the address itself */
169164562Sgshapiro		clt_addr.sa.sa_family = addr_family(p);
169264562Sgshapiro		switch (clt_addr.sa.sa_family)
169364562Sgshapiro		{
169464562Sgshapiro# if NETINET
169564562Sgshapiro		  case AF_INET:
169673188Sgshapiro			clt_addr.sin.sin_addr.s_addr = inet_addr(p);
169773188Sgshapiro			if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE &&
169873188Sgshapiro			    clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK)
169964562Sgshapiro			{
170064562Sgshapiro				clt_bind = TRUE;
170164562Sgshapiro				socksize = sizeof (struct sockaddr_in);
170264562Sgshapiro			}
170364562Sgshapiro			break;
170464562Sgshapiro# endif /* NETINET */
170564562Sgshapiro
170664562Sgshapiro# if NETINET6
170764562Sgshapiro		  case AF_INET6:
170864562Sgshapiro			if (inet_addr(p) != INADDR_NONE)
170964562Sgshapiro				snprintf(p6, sizeof p6, "::ffff:%s", p);
171064562Sgshapiro			else
171164562Sgshapiro				strlcpy(p6, p, sizeof p6);
171264562Sgshapiro			if (inet_pton(AF_INET6, p6,
171373188Sgshapiro				      &clt_addr.sin6.sin6_addr) == 1 &&
171473188Sgshapiro			    !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr))
171564562Sgshapiro			{
171664562Sgshapiro				clt_bind = TRUE;
171764562Sgshapiro				socksize = sizeof (struct sockaddr_in6);
171864562Sgshapiro			}
171964562Sgshapiro			break;
172064562Sgshapiro# endif /* NETINET6 */
172164562Sgshapiro
172264562Sgshapiro# if 0
172364562Sgshapiro		  default:
172464562Sgshapiro			syserr("554 5.3.5 Address= option unsupported for family %d",
172564562Sgshapiro			       clt_addr.sa.sa_family);
172664562Sgshapiro			break;
172764562Sgshapiro# endif /* 0 */
172864562Sgshapiro		}
172964562Sgshapiro		if (clt_bind)
173064562Sgshapiro			family = clt_addr.sa.sa_family;
173164562Sgshapiro	}
173264562Sgshapiro	else
173364562Sgshapiro	{
173464562Sgshapiro		STRUCTCOPY(ClientAddr, clt_addr);
173564562Sgshapiro		if (clt_addr.sa.sa_family == AF_UNSPEC)
173677349Sgshapiro			clt_addr.sa.sa_family = family;
173764562Sgshapiro		switch (clt_addr.sa.sa_family)
173864562Sgshapiro		{
173964562Sgshapiro# if NETINET
174064562Sgshapiro		  case AF_INET:
174164562Sgshapiro			if (clt_addr.sin.sin_addr.s_addr == 0)
174264562Sgshapiro				clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
174364562Sgshapiro			else
174464562Sgshapiro				clt_bind = TRUE;
174564562Sgshapiro			if (clt_addr.sin.sin_port != 0)
174664562Sgshapiro				clt_bind = TRUE;
174764562Sgshapiro			socksize = sizeof (struct sockaddr_in);
174864562Sgshapiro			break;
174964562Sgshapiro# endif /* NETINET */
175064562Sgshapiro# if NETINET6
175164562Sgshapiro		  case AF_INET6:
175264562Sgshapiro			if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
175364562Sgshapiro				clt_addr.sin6.sin6_addr = in6addr_any;
175464562Sgshapiro			else
175564562Sgshapiro				clt_bind = TRUE;
175664562Sgshapiro			socksize = sizeof (struct sockaddr_in6);
175764562Sgshapiro			if (clt_addr.sin6.sin6_port != 0)
175864562Sgshapiro				clt_bind = TRUE;
175964562Sgshapiro			break;
176064562Sgshapiro# endif /* NETINET6 */
176164562Sgshapiro# if NETISO
176264562Sgshapiro		  case AF_ISO:
176364562Sgshapiro			socksize = sizeof clt_addr.siso;
176464562Sgshapiro			clt_bind = TRUE;
176564562Sgshapiro			break;
176664562Sgshapiro# endif /* NETISO */
176764562Sgshapiro		  default:
176864562Sgshapiro			break;
176964562Sgshapiro		}
177064562Sgshapiro	}
177164562Sgshapiro
177238032Speter	/*
177338032Speter	**  Set up the address for the mailer.
177438032Speter	**	Accept "[a.b.c.d]" syntax for host name.
177538032Speter	*/
177638032Speter
177764562Sgshapiro# if NAMED_BIND
177873188Sgshapiro	SM_SET_H_ERRNO(0);
177964562Sgshapiro# endif /* NAMED_BIND */
178038032Speter	errno = 0;
178164562Sgshapiro	memset(&CurHostAddr, '\0', sizeof CurHostAddr);
178264562Sgshapiro	memset(&addr, '\0', sizeof addr);
178338032Speter	SmtpPhase = mci->mci_phase = "initial connection";
178438032Speter	CurHostName = host;
178538032Speter
178638032Speter	if (host[0] == '[')
178738032Speter	{
178864562Sgshapiro		p = strchr(host, ']');
178938032Speter		if (p != NULL)
179038032Speter		{
179164562Sgshapiro# if NETINET
179264562Sgshapiro			unsigned long hid = INADDR_NONE;
179364562Sgshapiro# endif /* NETINET */
179464562Sgshapiro# if NETINET6
179564562Sgshapiro			struct sockaddr_in6 hid6;
179664562Sgshapiro# endif /* NETINET6 */
179764562Sgshapiro
179838032Speter			*p = '\0';
179964562Sgshapiro# if NETINET6
180064562Sgshapiro			memset(&hid6, '\0', sizeof hid6);
180164562Sgshapiro# endif /* NETINET6 */
180264562Sgshapiro# if NETINET
180364562Sgshapiro			if (family == AF_INET &&
180464562Sgshapiro			    (hid = inet_addr(&host[1])) != INADDR_NONE)
180538032Speter			{
180664562Sgshapiro				addr.sin.sin_family = AF_INET;
180764562Sgshapiro				addr.sin.sin_addr.s_addr = hid;
180864562Sgshapiro			}
180964562Sgshapiro			else
181064562Sgshapiro# endif /* NETINET */
181164562Sgshapiro# if NETINET6
181264562Sgshapiro			if (family == AF_INET6 &&
181364562Sgshapiro			    inet_pton(AF_INET6, &host[1],
181464562Sgshapiro				      &hid6.sin6_addr) == 1)
181564562Sgshapiro			{
181664562Sgshapiro				addr.sin6.sin6_family = AF_INET6;
181764562Sgshapiro				addr.sin6.sin6_addr = hid6.sin6_addr;
181864562Sgshapiro			}
181964562Sgshapiro			else
182064562Sgshapiro# endif /* NETINET6 */
182164562Sgshapiro			{
182238032Speter				/* try it as a host name (avoid MX lookup) */
182364562Sgshapiro				hp = sm_gethostbyname(&host[1], family);
182438032Speter				if (hp == NULL && p[-1] == '.')
182538032Speter				{
182664562Sgshapiro# if NAMED_BIND
182738032Speter					int oldopts = _res.options;
182838032Speter
182938032Speter					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
183064562Sgshapiro# endif /* NAMED_BIND */
183138032Speter					p[-1] = '\0';
183264562Sgshapiro					hp = sm_gethostbyname(&host[1],
183364562Sgshapiro							      family);
183438032Speter					p[-1] = '.';
183564562Sgshapiro# if NAMED_BIND
183638032Speter					_res.options = oldopts;
183764562Sgshapiro# endif /* NAMED_BIND */
183838032Speter				}
183938032Speter				*p = ']';
184038032Speter				goto gothostent;
184138032Speter			}
184238032Speter			*p = ']';
184338032Speter		}
184438032Speter		if (p == NULL)
184538032Speter		{
184638032Speter			extern char MsgBuf[];
184738032Speter
184864562Sgshapiro			usrerrenh("5.1.2",
184964562Sgshapiro				  "553 Invalid numeric domain spec \"%s\"",
185064562Sgshapiro				  host);
185138032Speter			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
185264562Sgshapiro			errno = EINVAL;
185338032Speter			return EX_NOHOST;
185438032Speter		}
185538032Speter	}
185638032Speter	else
185738032Speter	{
185838032Speter		/* contortion to get around SGI cc complaints */
185938032Speter		{
186064562Sgshapiro			p = &host[strlen(host) - 1];
186164562Sgshapiro			hp = sm_gethostbyname(host, family);
186238032Speter			if (hp == NULL && *p == '.')
186338032Speter			{
186464562Sgshapiro# if NAMED_BIND
186538032Speter				int oldopts = _res.options;
186638032Speter
186738032Speter				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
186864562Sgshapiro# endif /* NAMED_BIND */
186938032Speter				*p = '\0';
187064562Sgshapiro				hp = sm_gethostbyname(host, family);
187138032Speter				*p = '.';
187264562Sgshapiro# if NAMED_BIND
187338032Speter				_res.options = oldopts;
187464562Sgshapiro# endif /* NAMED_BIND */
187538032Speter			}
187638032Speter		}
187738032Spetergothostent:
187838032Speter		if (hp == NULL)
187938032Speter		{
188064562Sgshapiro# if NAMED_BIND
188138032Speter			/* check for name server timeouts */
188238032Speter			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
188338032Speter			    (errno == ECONNREFUSED && UseNameServer))
188438032Speter			{
188564562Sgshapiro				save_errno = errno;
188638032Speter				mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
188764562Sgshapiro				errno = save_errno;
188838032Speter				return EX_TEMPFAIL;
188938032Speter			}
189064562Sgshapiro# endif /* NAMED_BIND */
189164562Sgshapiro# if NETINET6
189264562Sgshapiro			/*
189364562Sgshapiro			**  Try v6 first, then fall back to v4.
189464562Sgshapiro			**  If we found a v6 address, but no v4
189564562Sgshapiro			**  addresses, then TEMPFAIL.
189664562Sgshapiro			*/
189764562Sgshapiro
189864562Sgshapiro			if (family == AF_INET6)
189964562Sgshapiro			{
190064562Sgshapiro				family = AF_INET;
190164562Sgshapiro				goto v4retry;
190264562Sgshapiro			}
190364562Sgshapiro			if (v6found)
190464562Sgshapiro				goto v6tempfail;
190564562Sgshapiro# endif /* NETINET6 */
190664562Sgshapiro			save_errno = errno;
190738032Speter			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
190864562Sgshapiro			errno = save_errno;
190964562Sgshapiro			return EX_NOHOST;
191038032Speter		}
191138032Speter		addr.sa.sa_family = hp->h_addrtype;
191238032Speter		switch (hp->h_addrtype)
191338032Speter		{
191464562Sgshapiro# if NETINET
191538032Speter		  case AF_INET:
191664562Sgshapiro			memmove(&addr.sin.sin_addr,
191764562Sgshapiro				hp->h_addr,
191838032Speter				INADDRSZ);
191938032Speter			break;
192064562Sgshapiro# endif /* NETINET */
192138032Speter
192264562Sgshapiro# if NETINET6
192364562Sgshapiro		  case AF_INET6:
192464562Sgshapiro			memmove(&addr.sin6.sin6_addr,
192564562Sgshapiro				hp->h_addr,
192664562Sgshapiro				IN6ADDRSZ);
192764562Sgshapiro			break;
192864562Sgshapiro# endif /* NETINET6 */
192964562Sgshapiro
193038032Speter		  default:
193138032Speter			if (hp->h_length > sizeof addr.sa.sa_data)
193238032Speter			{
193338032Speter				syserr("makeconnection: long sa_data: family %d len %d",
193438032Speter					hp->h_addrtype, hp->h_length);
193538032Speter				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
193664562Sgshapiro				errno = EINVAL;
193738032Speter				return EX_NOHOST;
193838032Speter			}
193964562Sgshapiro			memmove(addr.sa.sa_data,
194064562Sgshapiro				hp->h_addr,
194138032Speter				hp->h_length);
194238032Speter			break;
194338032Speter		}
194438032Speter		addrno = 1;
194538032Speter	}
194638032Speter
194738032Speter	/*
194838032Speter	**  Determine the port number.
194938032Speter	*/
195038032Speter
195138032Speter	if (port == 0)
195238032Speter	{
195364562Sgshapiro# ifdef NO_GETSERVBYNAME
195464562Sgshapiro		port = htons(25);
195564562Sgshapiro# else /* NO_GETSERVBYNAME */
195638032Speter		register struct servent *sp = getservbyname("smtp", "tcp");
195738032Speter
195838032Speter		if (sp == NULL)
195938032Speter		{
196038032Speter			if (LogLevel > 2)
196138032Speter				sm_syslog(LOG_ERR, NOQID,
196264562Sgshapiro					  "makeconnection: service \"smtp\" unknown");
196338032Speter			port = htons(25);
196438032Speter		}
196538032Speter		else
196638032Speter			port = sp->s_port;
196764562Sgshapiro# endif /* NO_GETSERVBYNAME */
196838032Speter	}
196938032Speter
197038032Speter	switch (addr.sa.sa_family)
197138032Speter	{
197264562Sgshapiro# if NETINET
197338032Speter	  case AF_INET:
197438032Speter		addr.sin.sin_port = port;
197538032Speter		addrlen = sizeof (struct sockaddr_in);
197638032Speter		break;
197764562Sgshapiro# endif /* NETINET */
197838032Speter
197964562Sgshapiro# if NETINET6
198064562Sgshapiro	  case AF_INET6:
198164562Sgshapiro		addr.sin6.sin6_port = port;
198264562Sgshapiro		addrlen = sizeof (struct sockaddr_in6);
198364562Sgshapiro		break;
198464562Sgshapiro# endif /* NETINET6 */
198564562Sgshapiro
198664562Sgshapiro# if NETISO
198738032Speter	  case AF_ISO:
198838032Speter		/* assume two byte transport selector */
198964562Sgshapiro		memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
199038032Speter		addrlen = sizeof (struct sockaddr_iso);
199138032Speter		break;
199264562Sgshapiro# endif /* NETISO */
199338032Speter
199438032Speter	  default:
199538032Speter		syserr("Can't connect to address family %d", addr.sa.sa_family);
199638032Speter		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
199764562Sgshapiro		errno = EINVAL;
199871345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
199971345Sgshapiro		if (hp != NULL)
200071345Sgshapiro			freehostent(hp);
200171345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
200264562Sgshapiro		return EX_NOHOST;
200338032Speter	}
200438032Speter
200538032Speter	/*
200638032Speter	**  Try to actually open the connection.
200738032Speter	*/
200838032Speter
200964562Sgshapiro# ifdef XLA
201038032Speter	/* if too many connections, don't bother trying */
201138032Speter	if (!xla_noqueue_ok(host))
201271345Sgshapiro	{
201371345Sgshapiro#  if _FFR_FREEHOSTENT && NETINET6
201471345Sgshapiro		if (hp != NULL)
201571345Sgshapiro			freehostent(hp);
201671345Sgshapiro#  endif /* _FFR_FREEHOSTENT && NETINET6 */
201738032Speter		return EX_TEMPFAIL;
201871345Sgshapiro	}
201964562Sgshapiro# endif /* XLA */
202038032Speter
202138032Speter	firstconnect = TRUE;
202238032Speter	for (;;)
202338032Speter	{
202438032Speter		if (tTd(16, 1))
202577349Sgshapiro			dprintf("makeconnection (%s [%s].%d (%d))\n",
202677349Sgshapiro				host, anynet_ntoa(&addr), ntohs(port),
202777349Sgshapiro				addr.sa.sa_family);
202838032Speter
202938032Speter		/* save for logging */
203038032Speter		CurHostAddr = addr;
203138032Speter
203238032Speter		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
203338032Speter		{
203438032Speter			int rport = IPPORT_RESERVED - 1;
203538032Speter
203638032Speter			s = rresvport(&rport);
203738032Speter		}
203838032Speter		else
203938032Speter		{
204077349Sgshapiro			s = socket(clt_addr.sa.sa_family, SOCK_STREAM, 0);
204138032Speter		}
204238032Speter		if (s < 0)
204338032Speter		{
204464562Sgshapiro			save_errno = errno;
204538032Speter			syserr("makeconnection: cannot create socket");
204664562Sgshapiro# ifdef XLA
204738032Speter			xla_host_end(host);
204864562Sgshapiro# endif /* XLA */
204938032Speter			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
205071345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
205171345Sgshapiro			if (hp != NULL)
205271345Sgshapiro				freehostent(hp);
205371345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
205464562Sgshapiro			errno = save_errno;
205538032Speter			return EX_TEMPFAIL;
205638032Speter		}
205738032Speter
205864562Sgshapiro# ifdef SO_SNDBUF
205938032Speter		if (TcpSndBufferSize > 0)
206038032Speter		{
206138032Speter			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
206238032Speter				       (char *) &TcpSndBufferSize,
206338032Speter				       sizeof(TcpSndBufferSize)) < 0)
206438032Speter				syserr("makeconnection: setsockopt(SO_SNDBUF)");
206538032Speter		}
206664562Sgshapiro# endif /* SO_SNDBUF */
206764562Sgshapiro# ifdef SO_RCVBUF
206864562Sgshapiro		if (TcpRcvBufferSize > 0)
206964562Sgshapiro		{
207064562Sgshapiro			if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
207164562Sgshapiro				       (char *) &TcpRcvBufferSize,
207264562Sgshapiro				       sizeof(TcpRcvBufferSize)) < 0)
207364562Sgshapiro				syserr("makeconnection: setsockopt(SO_RCVBUF)");
207464562Sgshapiro		}
207564562Sgshapiro# endif /* SO_RCVBUF */
207638032Speter
207764562Sgshapiro
207838032Speter		if (tTd(16, 1))
207964562Sgshapiro			dprintf("makeconnection: fd=%d\n", s);
208038032Speter
208138032Speter		/* turn on network debugging? */
208238032Speter		if (tTd(16, 101))
208338032Speter		{
208438032Speter			int on = 1;
208564562Sgshapiro
208638032Speter			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
208738032Speter					  (char *)&on, sizeof on);
208838032Speter		}
208938032Speter		if (e->e_xfp != NULL)
209064562Sgshapiro			(void) fflush(e->e_xfp);	/* for debugging */
209164562Sgshapiro		errno = 0;				/* for debugging */
209238032Speter
209364562Sgshapiro		if (clt_bind)
209464562Sgshapiro		{
209564562Sgshapiro			int on = 1;
209664562Sgshapiro
209764562Sgshapiro			switch (clt_addr.sa.sa_family)
209864562Sgshapiro			{
209964562Sgshapiro# if NETINET
210064562Sgshapiro			  case AF_INET:
210164562Sgshapiro				if (clt_addr.sin.sin_port != 0)
210264562Sgshapiro					(void) setsockopt(s, SOL_SOCKET,
210364562Sgshapiro							  SO_REUSEADDR,
210464562Sgshapiro							  (char *) &on,
210564562Sgshapiro							  sizeof on);
210664562Sgshapiro				break;
210764562Sgshapiro# endif /* NETINET */
210864562Sgshapiro
210964562Sgshapiro# if NETINET6
211064562Sgshapiro			  case AF_INET6:
211164562Sgshapiro				if (clt_addr.sin6.sin6_port != 0)
211264562Sgshapiro					(void) setsockopt(s, SOL_SOCKET,
211364562Sgshapiro							  SO_REUSEADDR,
211464562Sgshapiro							  (char *) &on,
211564562Sgshapiro							  sizeof on);
211664562Sgshapiro				break;
211764562Sgshapiro# endif /* NETINET6 */
211864562Sgshapiro			}
211964562Sgshapiro
212064562Sgshapiro			if (bind(s, &clt_addr.sa, socksize) < 0)
212164562Sgshapiro			{
212264562Sgshapiro				save_errno = errno;
212364562Sgshapiro				(void) close(s);
212464562Sgshapiro				errno = save_errno;
212564562Sgshapiro				syserr("makeconnection: cannot bind socket [%s]",
212664562Sgshapiro				       anynet_ntoa(&clt_addr));
212771345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
212871345Sgshapiro				if (hp != NULL)
212971345Sgshapiro					freehostent(hp);
213071345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
213164562Sgshapiro				errno = save_errno;
213264562Sgshapiro				return EX_TEMPFAIL;
213364562Sgshapiro			}
213464562Sgshapiro		}
213564562Sgshapiro
213638032Speter		/*
213738032Speter		**  Linux seems to hang in connect for 90 minutes (!!!).
213838032Speter		**  Time out the connect to avoid this problem.
213938032Speter		*/
214038032Speter
214138032Speter		if (setjmp(CtxConnectTimeout) == 0)
214238032Speter		{
214338032Speter			int i;
214438032Speter
214538032Speter			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
214677349Sgshapiro				ev = setevent(TimeOuts.to_iconnect,
214777349Sgshapiro					      connecttimeout, 0);
214838032Speter			else if (TimeOuts.to_connect != 0)
214977349Sgshapiro				ev = setevent(TimeOuts.to_connect,
215077349Sgshapiro					      connecttimeout, 0);
215138032Speter			else
215238032Speter				ev = NULL;
215338032Speter
215464562Sgshapiro			switch (ConnectOnlyTo.sa.sa_family)
215564562Sgshapiro			{
215664562Sgshapiro# if NETINET
215764562Sgshapiro			  case AF_INET:
215864562Sgshapiro				addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
215964562Sgshapiro				break;
216064562Sgshapiro# endif /* NETINET */
216164562Sgshapiro
216264562Sgshapiro# if NETINET6
216364562Sgshapiro			  case AF_INET6:
216464562Sgshapiro				memmove(&addr.sin6.sin6_addr,
216564562Sgshapiro					&ConnectOnlyTo.sin6.sin6_addr,
216664562Sgshapiro					IN6ADDRSZ);
216764562Sgshapiro				break;
216864562Sgshapiro# endif /* NETINET6 */
216964562Sgshapiro			}
217038032Speter			i = connect(s, (struct sockaddr *) &addr, addrlen);
217164562Sgshapiro			save_errno = errno;
217238032Speter			if (ev != NULL)
217338032Speter				clrevent(ev);
217438032Speter			if (i >= 0)
217538032Speter				break;
217638032Speter		}
217738032Speter		else
217864562Sgshapiro			save_errno = errno;
217938032Speter
218038032Speter		/* if running demand-dialed connection, try again */
218138032Speter		if (DialDelay > 0 && firstconnect)
218238032Speter		{
218338032Speter			if (tTd(16, 1))
218464562Sgshapiro				dprintf("Connect failed (%s); trying again...\n",
218564562Sgshapiro					errstring(save_errno));
218638032Speter			firstconnect = FALSE;
218764562Sgshapiro			(void) sleep(DialDelay);
218838032Speter			continue;
218938032Speter		}
219038032Speter
219138032Speter		/* couldn't connect.... figure out why */
219238032Speter		(void) close(s);
219338032Speter
219438032Speter		if (LogLevel >= 14)
219538032Speter			sm_syslog(LOG_INFO, e->e_id,
219638032Speter				  "makeconnection (%s [%s]) failed: %s",
219738032Speter				  host, anynet_ntoa(&addr),
219864562Sgshapiro				  errstring(save_errno));
219938032Speter
220038032Speter		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
220138032Speter		{
220238032Speter			if (tTd(16, 1))
220364562Sgshapiro				dprintf("Connect failed (%s); trying new address....\n",
220464562Sgshapiro					errstring(save_errno));
220538032Speter			switch (addr.sa.sa_family)
220638032Speter			{
220764562Sgshapiro# if NETINET
220838032Speter			  case AF_INET:
220964562Sgshapiro				memmove(&addr.sin.sin_addr,
221064562Sgshapiro					hp->h_addr_list[addrno++],
221164562Sgshapiro					INADDRSZ);
221238032Speter				break;
221364562Sgshapiro# endif /* NETINET */
221438032Speter
221564562Sgshapiro# if NETINET6
221664562Sgshapiro			  case AF_INET6:
221764562Sgshapiro				memmove(&addr.sin6.sin6_addr,
221864562Sgshapiro					hp->h_addr_list[addrno++],
221964562Sgshapiro					IN6ADDRSZ);
222064562Sgshapiro				break;
222164562Sgshapiro# endif /* NETINET6 */
222264562Sgshapiro
222338032Speter			  default:
222464562Sgshapiro				memmove(addr.sa.sa_data,
222564562Sgshapiro					hp->h_addr_list[addrno++],
222638032Speter					hp->h_length);
222738032Speter				break;
222838032Speter			}
222938032Speter			continue;
223038032Speter		}
223164562Sgshapiro		errno = save_errno;
223238032Speter
223364562Sgshapiro# if NETINET6
223464562Sgshapiro		if (family == AF_INET6)
223564562Sgshapiro		{
223664562Sgshapiro			if (tTd(16, 1))
223764562Sgshapiro				dprintf("Connect failed (%s); retrying with AF_INET....\n",
223864562Sgshapiro					errstring(save_errno));
223964562Sgshapiro			v6found = TRUE;
224064562Sgshapiro			family = AF_INET;
224171345Sgshapiro#  if _FFR_FREEHOSTENT
224271345Sgshapiro			if (hp != NULL)
224371345Sgshapiro			{
224471345Sgshapiro				freehostent(hp);
224571345Sgshapiro				hp = NULL;
224671345Sgshapiro			}
224771345Sgshapiro#  endif /* _FFR_FREEHOSTENT */
224864562Sgshapiro			goto v4retry;
224964562Sgshapiro		}
225064562Sgshapiro	v6tempfail:
225164562Sgshapiro# endif /* NETINET6 */
225238032Speter		/* couldn't open connection */
225364562Sgshapiro# if NETINET6
225464562Sgshapiro		/* Don't clobber an already saved errno from v4retry */
225564562Sgshapiro		if (errno > 0)
225664562Sgshapiro# endif /* NETINET6 */
225764562Sgshapiro			save_errno = errno;
225864562Sgshapiro		if (tTd(16, 1))
225964562Sgshapiro			dprintf("Connect failed (%s)\n", errstring(save_errno));
226064562Sgshapiro# ifdef XLA
226138032Speter		xla_host_end(host);
226264562Sgshapiro# endif /* XLA */
226338032Speter		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
226471345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
226571345Sgshapiro		if (hp != NULL)
226671345Sgshapiro			freehostent(hp);
226771345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
226864562Sgshapiro		errno = save_errno;
226938032Speter		return EX_TEMPFAIL;
227038032Speter	}
227138032Speter
227271345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
227371345Sgshapiro	if (hp != NULL)
227471345Sgshapiro	{
227571345Sgshapiro		freehostent(hp);
227671345Sgshapiro		hp = NULL;
227771345Sgshapiro	}
227871345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
227971345Sgshapiro
228038032Speter	/* connection ok, put it into canonical form */
228164562Sgshapiro	mci->mci_out = NULL;
228238032Speter	if ((mci->mci_out = fdopen(s, "w")) == NULL ||
228338032Speter	    (s = dup(s)) < 0 ||
228438032Speter	    (mci->mci_in = fdopen(s, "r")) == NULL)
228538032Speter	{
228664562Sgshapiro		save_errno = errno;
228738032Speter		syserr("cannot open SMTP client channel, fd=%d", s);
228838032Speter		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
228964562Sgshapiro		if (mci->mci_out != NULL)
229064562Sgshapiro			(void) fclose(mci->mci_out);
229164562Sgshapiro		(void) close(s);
229264562Sgshapiro		errno = save_errno;
229338032Speter		return EX_TEMPFAIL;
229438032Speter	}
229538032Speter
229664562Sgshapiro	/* find out name for Interface through which we connect */
229764562Sgshapiro	len = sizeof addr;
229864562Sgshapiro	if (getsockname(s, &addr.sa, &len) == 0)
229964562Sgshapiro	{
230064562Sgshapiro		char *name;
230164562Sgshapiro		char *p;
230264562Sgshapiro
230364562Sgshapiro		define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)),
230464562Sgshapiro		       &BlankEnvelope);
230564562Sgshapiro		p = xalloc(5);
230664562Sgshapiro		snprintf(p, 4, "%d", addr.sa.sa_family);
230764562Sgshapiro		define(macid("{if_family}", NULL), p, &BlankEnvelope);
230864562Sgshapiro
230964562Sgshapiro		name = hostnamebyanyaddr(&addr);
231064562Sgshapiro		define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope);
231164562Sgshapiro		if (LogLevel > 11)
231264562Sgshapiro		{
231364562Sgshapiro			/* log connection information */
231464562Sgshapiro			sm_syslog(LOG_INFO, e->e_id,
231564562Sgshapiro				  "SMTP outgoing connect on %.40s", name);
231664562Sgshapiro		}
231764562Sgshapiro		if (bitnset(D_IFNHELO, d_flags))
231864562Sgshapiro		{
231964562Sgshapiro			if (name[0] != '[' && strchr(name, '.') != NULL)
232064562Sgshapiro				mci->mci_heloname = newstr(name);
232164562Sgshapiro		}
232264562Sgshapiro	}
232364562Sgshapiro	else
232464562Sgshapiro	{
232564562Sgshapiro		define(macid("{if_name}", NULL), NULL, &BlankEnvelope);
232664562Sgshapiro		define(macid("{if_addr}", NULL), NULL, &BlankEnvelope);
232764562Sgshapiro		define(macid("{if_family}", NULL), NULL, &BlankEnvelope);
232864562Sgshapiro	}
232938032Speter	mci_setstat(mci, EX_OK, NULL, NULL);
233064562Sgshapiro	return EX_OK;
233138032Speter}
233264562Sgshapiro
233364562Sgshapirostatic void
233464562Sgshapiroconnecttimeout()
233564562Sgshapiro{
233677349Sgshapiro	/*
233777349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
233877349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
233977349Sgshapiro	**	DOING.
234077349Sgshapiro	*/
234177349Sgshapiro
234264562Sgshapiro	errno = ETIMEDOUT;
234364562Sgshapiro	longjmp(CtxConnectTimeout, 1);
234464562Sgshapiro}
234538032Speter/*
234664562Sgshapiro**  MAKECONNECTION_DS -- make a connection to a domain socket.
234764562Sgshapiro**
234864562Sgshapiro**	Parameters:
234964562Sgshapiro**		mux_path -- the path of the socket to connect to.
235064562Sgshapiro**		mci -- a pointer to the mail connection information
235164562Sgshapiro**			structure to be filled in.
235264562Sgshapiro**
235364562Sgshapiro**	Returns:
235464562Sgshapiro**		An exit code telling whether the connection could be
235564562Sgshapiro**			made and if not why not.
235664562Sgshapiro**
235764562Sgshapiro**	Side Effects:
235864562Sgshapiro**		none.
235964562Sgshapiro*/
236064562Sgshapiro
236164562Sgshapiro# if NETUNIX
236264562Sgshapiroint makeconnection_ds(mux_path, mci)
236364562Sgshapiro	char *mux_path;
236464562Sgshapiro	register MCI *mci;
236564562Sgshapiro{
236664562Sgshapiro	int sock;
236764562Sgshapiro	int rval, save_errno;
236864562Sgshapiro	long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
236964562Sgshapiro	struct sockaddr_un unix_addr;
237064562Sgshapiro
237164562Sgshapiro	/* if not safe, don't connect */
237264562Sgshapiro	rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
237364562Sgshapiro			sff, S_IRUSR|S_IWUSR, NULL);
237464562Sgshapiro
237564562Sgshapiro	if (rval != 0)
237664562Sgshapiro	{
237764562Sgshapiro		syserr("makeconnection_ds: unsafe domain socket");
237864562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
237964562Sgshapiro		errno = rval;
238064562Sgshapiro		return EX_TEMPFAIL;
238164562Sgshapiro	}
238264562Sgshapiro
238364562Sgshapiro	/* prepare address structure */
238464562Sgshapiro	memset(&unix_addr, '\0', sizeof unix_addr);
238564562Sgshapiro	unix_addr.sun_family = AF_UNIX;
238664562Sgshapiro
238764562Sgshapiro	if (strlen(mux_path) >= sizeof unix_addr.sun_path)
238864562Sgshapiro	{
238964562Sgshapiro		syserr("makeconnection_ds: domain socket name too long");
239064562Sgshapiro		/* XXX why TEMPFAIL ? */
239164562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
239264562Sgshapiro		errno = ENAMETOOLONG;
239364562Sgshapiro		return EX_UNAVAILABLE;
239464562Sgshapiro	}
239564562Sgshapiro	(void) strlcpy(unix_addr.sun_path, mux_path, sizeof unix_addr.sun_path);
239664562Sgshapiro
239764562Sgshapiro	/* initialize domain socket */
239864562Sgshapiro	sock = socket(AF_UNIX, SOCK_STREAM, 0);
239964562Sgshapiro	if (sock == -1)
240064562Sgshapiro	{
240164562Sgshapiro		save_errno = errno;
240264562Sgshapiro		syserr("makeconnection_ds: could not create domain socket");
240364562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
240464562Sgshapiro		errno = save_errno;
240564562Sgshapiro		return EX_TEMPFAIL;
240664562Sgshapiro	}
240764562Sgshapiro
240864562Sgshapiro	/* connect to server */
240964562Sgshapiro	if (connect(sock, (struct sockaddr *) &unix_addr,
241064562Sgshapiro		    sizeof(unix_addr)) == -1)
241164562Sgshapiro	{
241264562Sgshapiro		save_errno = errno;
241364562Sgshapiro		syserr("Could not connect to socket %s", mux_path);
241464562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
241564562Sgshapiro		(void) close(sock);
241664562Sgshapiro		errno = save_errno;
241764562Sgshapiro		return EX_TEMPFAIL;
241864562Sgshapiro	}
241964562Sgshapiro
242064562Sgshapiro	/* connection ok, put it into canonical form */
242164562Sgshapiro	mci->mci_out = NULL;
242264562Sgshapiro	if ((mci->mci_out = fdopen(sock, "w")) == NULL ||
242364562Sgshapiro	    (sock = dup(sock)) < 0 ||
242464562Sgshapiro	    (mci->mci_in = fdopen(sock, "r")) == NULL)
242564562Sgshapiro	{
242664562Sgshapiro		save_errno = errno;
242764562Sgshapiro		syserr("cannot open SMTP client channel, fd=%d", sock);
242864562Sgshapiro		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
242964562Sgshapiro		if (mci->mci_out != NULL)
243064562Sgshapiro			(void) fclose(mci->mci_out);
243164562Sgshapiro		(void) close(sock);
243264562Sgshapiro		errno = save_errno;
243364562Sgshapiro		return EX_TEMPFAIL;
243464562Sgshapiro	}
243564562Sgshapiro
243664562Sgshapiro	mci_setstat(mci, EX_OK, NULL, NULL);
243764562Sgshapiro	errno = 0;
243864562Sgshapiro	return EX_OK;
243964562Sgshapiro}
244064562Sgshapiro# endif /* NETUNIX */
244164562Sgshapiro/*
244277349Sgshapiro**  SIGHUP -- handle a SIGHUP signal
244377349Sgshapiro**
244477349Sgshapiro**	Parameters:
244577349Sgshapiro**		sig -- incoming signal.
244677349Sgshapiro**
244777349Sgshapiro**	Returns:
244877349Sgshapiro**		none.
244977349Sgshapiro**
245077349Sgshapiro**	Side Effects:
245177349Sgshapiro**		Sets RestartRequest which should cause the daemon
245277349Sgshapiro**		to restart.
245377349Sgshapiro**
245477349Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
245577349Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
245677349Sgshapiro**		DOING.
245777349Sgshapiro*/
245877349Sgshapiro
245977349Sgshapiro/* ARGSUSED */
246077349Sgshapirostatic SIGFUNC_DECL
246177349Sgshapirosighup(sig)
246277349Sgshapiro	int sig;
246377349Sgshapiro{
246477349Sgshapiro	int save_errno = errno;
246577349Sgshapiro
246677349Sgshapiro	FIX_SYSV_SIGNAL(sig, sighup);
246777349Sgshapiro	RestartRequest = "signal";
246877349Sgshapiro	errno = save_errno;
246977349Sgshapiro	return SIGFUNC_RETURN;
247077349Sgshapiro}
247177349Sgshapiro/*
247277349Sgshapiro**  RESTART_DAEMON -- Performs a clean restart of the daemon
247377349Sgshapiro**
247477349Sgshapiro**	Parameters:
247577349Sgshapiro**		none.
247677349Sgshapiro**
247777349Sgshapiro**	Returns:
247877349Sgshapiro**		none.
247977349Sgshapiro**
248077349Sgshapiro**	Side Effects:
248177349Sgshapiro**		restarts the daemon or exits if restart fails.
248277349Sgshapiro*/
248377349Sgshapiro
248480785Sgshapiro/* Make a non-DFL/IGN signal a noop */
248580785Sgshapiro#define SM_NOOP_SIGNAL(sig, old)				\
248680785Sgshapirodo								\
248780785Sgshapiro{								\
248880785Sgshapiro	(old) = setsignal((sig), sm_signal_noop);		\
248980785Sgshapiro	if ((old) == SIG_IGN || (old) == SIG_DFL)		\
249080785Sgshapiro		(void) setsignal((sig), (old));			\
249180785Sgshapiro} while (0)
249280785Sgshapiro
249377349Sgshapirostatic void
249477349Sgshapirorestart_daemon()
249577349Sgshapiro{
249677349Sgshapiro	int i;
249777349Sgshapiro	int save_errno;
249877349Sgshapiro	char *reason;
249980785Sgshapiro	sigfunc_t ignore, oalrm, ousr1;
250077349Sgshapiro	extern int DtableSize;
250177349Sgshapiro
250280785Sgshapiro	/* clear the events to turn off SIGALRMs */
250380785Sgshapiro	clear_events();
250477349Sgshapiro	allsignals(TRUE);
250577349Sgshapiro
250677349Sgshapiro	reason = RestartRequest;
250777349Sgshapiro	RestartRequest = NULL;
250877349Sgshapiro	PendingSignal = 0;
250977349Sgshapiro
251077349Sgshapiro	if (SaveArgv[0][0] != '/')
251177349Sgshapiro	{
251277349Sgshapiro		if (LogLevel > 3)
251377349Sgshapiro			sm_syslog(LOG_INFO, NOQID,
251477349Sgshapiro				  "could not restart: need full path");
251577349Sgshapiro		finis(FALSE, EX_OSFILE);
251677349Sgshapiro	}
251777349Sgshapiro	if (LogLevel > 3)
251877349Sgshapiro		sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s",
251977349Sgshapiro			  SaveArgv[0],
252077349Sgshapiro			  reason == NULL ? "implicit call" : reason);
252177349Sgshapiro
252277349Sgshapiro	closecontrolsocket(TRUE);
252377349Sgshapiro	if (drop_privileges(TRUE) != EX_OK)
252477349Sgshapiro	{
252577349Sgshapiro		if (LogLevel > 0)
252677349Sgshapiro			sm_syslog(LOG_ALERT, NOQID,
252777349Sgshapiro				  "could not set[ug]id(%d, %d): %m",
252877349Sgshapiro				  RunAsUid, RunAsGid);
252977349Sgshapiro		finis(FALSE, EX_OSERR);
253077349Sgshapiro	}
253177349Sgshapiro
253277349Sgshapiro	/* arrange for all the files to be closed */
253377349Sgshapiro	for (i = 3; i < DtableSize; i++)
253477349Sgshapiro	{
253577349Sgshapiro		register int j;
253677349Sgshapiro
253777349Sgshapiro		if ((j = fcntl(i, F_GETFD, 0)) != -1)
253877349Sgshapiro			(void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
253977349Sgshapiro	}
254077349Sgshapiro
254180785Sgshapiro	/*
254280785Sgshapiro	**  Need to allow signals before execve() to make them "harmless".
254380785Sgshapiro	**  However, the default action can be "terminate", so it isn't
254480785Sgshapiro	**  really harmless.  Setting signals to IGN will cause them to be
254580785Sgshapiro	**  ignored in the new process to, so that isn't a good alternative.
254680785Sgshapiro	*/
254780785Sgshapiro
254880785Sgshapiro	SM_NOOP_SIGNAL(SIGALRM, oalrm);
254980785Sgshapiro	SM_NOOP_SIGNAL(SIGCHLD, ignore);
255080785Sgshapiro	SM_NOOP_SIGNAL(SIGHUP, ignore);
255180785Sgshapiro	SM_NOOP_SIGNAL(SIGINT, ignore);
255280785Sgshapiro	SM_NOOP_SIGNAL(SIGPIPE, ignore);
255380785Sgshapiro	SM_NOOP_SIGNAL(SIGTERM, ignore);
255480785Sgshapiro#ifdef SIGUSR1
255580785Sgshapiro	SM_NOOP_SIGNAL(SIGUSR1, ousr1);
255680785Sgshapiro#endif /* SIGUSR1 */
255777349Sgshapiro	allsignals(FALSE);
255877349Sgshapiro
255977349Sgshapiro	(void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
256077349Sgshapiro	save_errno = errno;
256177349Sgshapiro
256280785Sgshapiro	/* block signals again and restore needed signals */
256377349Sgshapiro	allsignals(TRUE);
256480785Sgshapiro
256580785Sgshapiro	/* For finis() events */
256677349Sgshapiro	(void) setsignal(SIGALRM, oalrm);
256780785Sgshapiro
256880785Sgshapiro#ifdef SIGUSR1
256980785Sgshapiro	/* For debugging finis() */
257077349Sgshapiro	(void) setsignal(SIGUSR1, ousr1);
257180785Sgshapiro#endif /* SIGUSR1 */
257277349Sgshapiro
257377349Sgshapiro	errno = save_errno;
257477349Sgshapiro	if (LogLevel > 0)
257577349Sgshapiro		sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m",
257677349Sgshapiro			  SaveArgv[0]);
257777349Sgshapiro	finis(FALSE, EX_OSFILE);
257877349Sgshapiro}
257977349Sgshapiro/*
258038032Speter**  MYHOSTNAME -- return the name of this host.
258138032Speter**
258238032Speter**	Parameters:
258338032Speter**		hostbuf -- a place to return the name of this host.
258438032Speter**		size -- the size of hostbuf.
258538032Speter**
258638032Speter**	Returns:
258738032Speter**		A list of aliases for this host.
258838032Speter**
258938032Speter**	Side Effects:
259038032Speter**		Adds numeric codes to $=w.
259138032Speter*/
259238032Speter
259338032Speterstruct hostent *
259438032Spetermyhostname(hostbuf, size)
259538032Speter	char hostbuf[];
259638032Speter	int size;
259738032Speter{
259838032Speter	register struct hostent *hp;
259938032Speter
260073188Sgshapiro	if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0')
260164562Sgshapiro		(void) strlcpy(hostbuf, "localhost", size);
260264562Sgshapiro	hp = sm_gethostbyname(hostbuf, InetMode);
260380785Sgshapiro# if NETINET && NETINET6
260480785Sgshapiro	if (hp == NULL && InetMode == AF_INET6)
260580785Sgshapiro	{
260680785Sgshapiro		/*
260780785Sgshapiro		**  It's possible that this IPv6 enabled machine doesn't
260880785Sgshapiro		**  actually have any IPv6 interfaces and, therefore, no
260980785Sgshapiro		**  IPv6 addresses.  Fall back to AF_INET.
261080785Sgshapiro		*/
261180785Sgshapiro
261280785Sgshapiro		hp = sm_gethostbyname(hostbuf, AF_INET);
261380785Sgshapiro	}
261480785Sgshapiro# endif /* NETINET && NETINET6 */
261580785Sgshapiro
261638032Speter	if (hp == NULL)
261738032Speter		return NULL;
261838032Speter	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
261964562Sgshapiro		(void) cleanstrcpy(hostbuf, hp->h_name, size);
262064562Sgshapiro
262164562Sgshapiro# if NETINFO
262264562Sgshapiro	if (strchr(hostbuf, '.') == NULL)
262338032Speter	{
262464562Sgshapiro		char *domainname;
262564562Sgshapiro
262664562Sgshapiro		domainname = ni_propval("/locations", NULL, "resolver",
262764562Sgshapiro					"domain", '\0');
262864562Sgshapiro		if (domainname != NULL &&
262964562Sgshapiro		    strlen(domainname) + strlen(hostbuf) + 1 < size)
263064562Sgshapiro		{
263164562Sgshapiro			(void) strlcat(hostbuf, ".", size);
263264562Sgshapiro			(void) strlcat(hostbuf, domainname, size);
263364562Sgshapiro		}
263438032Speter	}
263564562Sgshapiro# endif /* NETINFO */
263638032Speter
263738032Speter	/*
263838032Speter	**  If there is still no dot in the name, try looking for a
263938032Speter	**  dotted alias.
264038032Speter	*/
264138032Speter
264238032Speter	if (strchr(hostbuf, '.') == NULL)
264338032Speter	{
264438032Speter		char **ha;
264538032Speter
264664562Sgshapiro		for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
264738032Speter		{
264838032Speter			if (strchr(*ha, '.') != NULL)
264938032Speter			{
265064562Sgshapiro				(void) cleanstrcpy(hostbuf, *ha, size - 1);
265138032Speter				hostbuf[size - 1] = '\0';
265238032Speter				break;
265338032Speter			}
265438032Speter		}
265538032Speter	}
265638032Speter
265738032Speter	/*
265838032Speter	**  If _still_ no dot, wait for a while and try again -- it is
265938032Speter	**  possible that some service is starting up.  This can result
266038032Speter	**  in excessive delays if the system is badly configured, but
266138032Speter	**  there really isn't a way around that, particularly given that
266238032Speter	**  the config file hasn't been read at this point.
266338032Speter	**  All in all, a bit of a mess.
266438032Speter	*/
266538032Speter
266638032Speter	if (strchr(hostbuf, '.') == NULL &&
266738032Speter	    !getcanonname(hostbuf, size, TRUE))
266838032Speter	{
266938032Speter		sm_syslog(LOG_CRIT, NOQID,
267064562Sgshapiro			  "My unqualified host name (%s) unknown; sleeping for retry",
267164562Sgshapiro			  hostbuf);
267238032Speter		message("My unqualified host name (%s) unknown; sleeping for retry",
267338032Speter			hostbuf);
267464562Sgshapiro		(void) sleep(60);
267538032Speter		if (!getcanonname(hostbuf, size, TRUE))
267638032Speter		{
267738032Speter			sm_syslog(LOG_ALERT, NOQID,
267864562Sgshapiro				  "unable to qualify my own domain name (%s) -- using short name",
267964562Sgshapiro				  hostbuf);
268038032Speter			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
268138032Speter				hostbuf);
268238032Speter		}
268338032Speter	}
268464562Sgshapiro	return hp;
268538032Speter}
268638032Speter/*
268738032Speter**  ADDRCMP -- compare two host addresses
268838032Speter**
268938032Speter**	Parameters:
269038032Speter**		hp -- hostent structure for the first address
269138032Speter**		ha -- actual first address
269238032Speter**		sa -- second address
269338032Speter**
269438032Speter**	Returns:
269538032Speter**		0 -- if ha and sa match
269638032Speter**		else -- they don't match
269738032Speter*/
269838032Speter
269964562Sgshapirostatic int
270038032Speteraddrcmp(hp, ha, sa)
270138032Speter	struct hostent *hp;
270238032Speter	char *ha;
270338032Speter	SOCKADDR *sa;
270438032Speter{
270564562Sgshapiro# if NETINET6
270664562Sgshapiro	u_char *a;
270764562Sgshapiro# endif /* NETINET6 */
270864562Sgshapiro
270938032Speter	switch (sa->sa.sa_family)
271038032Speter	{
271164562Sgshapiro# if NETINET
271238032Speter	  case AF_INET:
271338032Speter		if (hp->h_addrtype == AF_INET)
271464562Sgshapiro			return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
271538032Speter		break;
271664562Sgshapiro# endif /* NETINET */
271738032Speter
271864562Sgshapiro# if NETINET6
271964562Sgshapiro	  case AF_INET6:
272064562Sgshapiro		a = (u_char *) &sa->sin6.sin6_addr;
272164562Sgshapiro
272264562Sgshapiro		/* Straight binary comparison */
272364562Sgshapiro		if (hp->h_addrtype == AF_INET6)
272464562Sgshapiro			return memcmp(ha, a, IN6ADDRSZ);
272564562Sgshapiro
272664562Sgshapiro		/* If IPv4-mapped IPv6 address, compare the IPv4 section */
272764562Sgshapiro		if (hp->h_addrtype == AF_INET &&
272864562Sgshapiro		    IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
272964562Sgshapiro			return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
273064562Sgshapiro		break;
273164562Sgshapiro# endif /* NETINET6 */
273238032Speter	}
273338032Speter	return -1;
273438032Speter}
273538032Speter/*
273664562Sgshapiro**  GETAUTHINFO -- get the real host name associated with a file descriptor
273738032Speter**
273838032Speter**	Uses RFC1413 protocol to try to get info from the other end.
273938032Speter**
274038032Speter**	Parameters:
274138032Speter**		fd -- the descriptor
274238032Speter**		may_be_forged -- an outage that is set to TRUE if the
274338032Speter**			forward lookup of RealHostName does not match
274438032Speter**			RealHostAddr; set to FALSE if they do match.
274538032Speter**
274638032Speter**	Returns:
274738032Speter**		The user@host information associated with this descriptor.
274838032Speter*/
274938032Speter
275038032Speterstatic jmp_buf	CtxAuthTimeout;
275138032Speter
275238032Speterstatic void
275338032Speterauthtimeout()
275438032Speter{
275577349Sgshapiro	/*
275677349Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
275777349Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
275877349Sgshapiro	**	DOING.
275977349Sgshapiro	*/
276077349Sgshapiro
276177349Sgshapiro	errno = ETIMEDOUT;
276238032Speter	longjmp(CtxAuthTimeout, 1);
276338032Speter}
276438032Speter
276538032Speterchar *
276638032Spetergetauthinfo(fd, may_be_forged)
276738032Speter	int fd;
276838032Speter	bool *may_be_forged;
276938032Speter{
277066494Sgshapiro	volatile u_short port = 0;
277138032Speter	SOCKADDR_LEN_T falen;
277238032Speter	register char *volatile p = NULL;
277338032Speter	SOCKADDR la;
277438032Speter	SOCKADDR_LEN_T lalen;
277538032Speter	register struct servent *sp;
277638032Speter	volatile int s;
277738032Speter	int i = 0;
277838032Speter	EVENT *ev;
277938032Speter	int nleft;
278038032Speter	struct hostent *hp;
278138032Speter	char *ostype = NULL;
278238032Speter	char **ha;
278338032Speter	char ibuf[MAXNAME + 1];
278438032Speter	static char hbuf[MAXNAME * 2 + 11];
278538032Speter
278638032Speter	*may_be_forged = FALSE;
278738032Speter	falen = sizeof RealHostAddr;
278838032Speter	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
278938032Speter	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
279038032Speter	{
279164562Sgshapiro		if (i < 0)
279264562Sgshapiro		{
279364562Sgshapiro			/*
279464562Sgshapiro			**  ENOTSOCK is OK: bail on anything else, but reset
279564562Sgshapiro			**  errno in this case, so a mis-report doesn't
279664562Sgshapiro			**  happen later.
279764562Sgshapiro			*/
279864562Sgshapiro			if (errno != ENOTSOCK)
279964562Sgshapiro				return NULL;
280064562Sgshapiro			errno = 0;
280164562Sgshapiro		}
280238032Speter		(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
280371345Sgshapiro				RealUserName);
280438032Speter		if (tTd(9, 1))
280564562Sgshapiro			dprintf("getauthinfo: %s\n", hbuf);
280638032Speter		return hbuf;
280738032Speter	}
280838032Speter
280938032Speter	if (RealHostName == NULL)
281038032Speter	{
281138032Speter		/* translate that to a host name */
281238032Speter		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
281338032Speter		if (strlen(RealHostName) > MAXNAME)
281442575Speter			RealHostName[MAXNAME] = '\0';
281538032Speter	}
281638032Speter
281738032Speter	/* cross check RealHostName with forward DNS lookup */
281838032Speter	if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
281938032Speter	    RealHostName[0] == '[')
282038032Speter	{
282138032Speter		/*
282242575Speter		**  address is not a socket or have an
282342575Speter		**  IP address with no forward lookup
282438032Speter		*/
282538032Speter		*may_be_forged = FALSE;
282638032Speter	}
282738032Speter	else
282838032Speter	{
282980785Sgshapiro		int family;
283080785Sgshapiro
283180785Sgshapiro		family = RealHostAddr.sa.sa_family;
283280785Sgshapiro# if NETINET6 && NEEDSGETIPNODE
283380785Sgshapiro		/*
283480785Sgshapiro		**  If RealHostAddr is an IPv6 connection with an
283580785Sgshapiro		**  IPv4-mapped address, we need RealHostName's IPv4
283680785Sgshapiro		**  address(es) for addrcmp() to compare against
283780785Sgshapiro		**  RealHostAddr.
283880785Sgshapiro		**
283980785Sgshapiro		**  Actually, we only need to do this for systems
284080785Sgshapiro		**  which NEEDSGETIPNODE since the real getipnodebyname()
284180785Sgshapiro		**  already does V4MAPPED address via the AI_V4MAPPEDCFG
284280785Sgshapiro		**  flag.  A better fix to this problem is to add this
284380785Sgshapiro		**  functionality to our stub getipnodebyname().
284480785Sgshapiro		*/
284580785Sgshapiro
284680785Sgshapiro		if (family == AF_INET6 &&
284780785Sgshapiro		    IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr))
284880785Sgshapiro			family = AF_INET;
284980785Sgshapiro# endif /* NETINET6 && NEEDSGETIPNODE */
285080785Sgshapiro
285138032Speter		/* try to match the reverse against the forward lookup */
285280785Sgshapiro		hp = sm_gethostbyname(RealHostName, family);
285338032Speter		if (hp == NULL)
285438032Speter			*may_be_forged = TRUE;
285538032Speter		else
285638032Speter		{
285738032Speter			for (ha = hp->h_addr_list; *ha != NULL; ha++)
285838032Speter				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
285938032Speter					break;
286038032Speter			*may_be_forged = *ha == NULL;
286171345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
286271345Sgshapiro			freehostent(hp);
286371345Sgshapiro			hp = NULL;
286471345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
286538032Speter		}
286638032Speter	}
286738032Speter
286838032Speter	if (TimeOuts.to_ident == 0)
286938032Speter		goto noident;
287038032Speter
287138032Speter	lalen = sizeof la;
287264562Sgshapiro	switch (RealHostAddr.sa.sa_family)
287338032Speter	{
287464562Sgshapiro# if NETINET
287564562Sgshapiro	  case AF_INET:
287664562Sgshapiro		if (getsockname(fd, &la.sa, &lalen) < 0 ||
287764562Sgshapiro		    lalen <= 0 ||
287864562Sgshapiro		    la.sa.sa_family != AF_INET)
287964562Sgshapiro		{
288064562Sgshapiro			/* no ident info */
288164562Sgshapiro			goto noident;
288264562Sgshapiro		}
288364562Sgshapiro		port = RealHostAddr.sin.sin_port;
288438032Speter
288564562Sgshapiro		/* create ident query */
288664562Sgshapiro		(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
288764562Sgshapiro				ntohs(RealHostAddr.sin.sin_port),
288864562Sgshapiro				ntohs(la.sin.sin_port));
288938032Speter
289064562Sgshapiro		/* create local address */
289164562Sgshapiro		la.sin.sin_port = 0;
289238032Speter
289364562Sgshapiro		/* create foreign address */
289464562Sgshapiro#  ifdef NO_GETSERVBYNAME
289538032Speter		RealHostAddr.sin.sin_port = htons(113);
289664562Sgshapiro#  else /* NO_GETSERVBYNAME */
289764562Sgshapiro		sp = getservbyname("auth", "tcp");
289864562Sgshapiro		if (sp != NULL)
289964562Sgshapiro			RealHostAddr.sin.sin_port = sp->s_port;
290064562Sgshapiro		else
290164562Sgshapiro			RealHostAddr.sin.sin_port = htons(113);
290264562Sgshapiro		break;
290364562Sgshapiro#  endif /* NO_GETSERVBYNAME */
290464562Sgshapiro# endif /* NETINET */
290538032Speter
290664562Sgshapiro# if NETINET6
290764562Sgshapiro	  case AF_INET6:
290864562Sgshapiro		if (getsockname(fd, &la.sa, &lalen) < 0 ||
290964562Sgshapiro		    lalen <= 0 ||
291064562Sgshapiro		    la.sa.sa_family != AF_INET6)
291164562Sgshapiro		{
291264562Sgshapiro			/* no ident info */
291364562Sgshapiro			goto noident;
291464562Sgshapiro		}
291564562Sgshapiro		port = RealHostAddr.sin6.sin6_port;
291664562Sgshapiro
291764562Sgshapiro		/* create ident query */
291864562Sgshapiro		(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
291964562Sgshapiro				ntohs(RealHostAddr.sin6.sin6_port),
292064562Sgshapiro				ntohs(la.sin6.sin6_port));
292164562Sgshapiro
292264562Sgshapiro		/* create local address */
292364562Sgshapiro		la.sin6.sin6_port = 0;
292464562Sgshapiro
292564562Sgshapiro		/* create foreign address */
292664562Sgshapiro#  ifdef NO_GETSERVBYNAME
292764562Sgshapiro		RealHostAddr.sin6.sin6_port = htons(113);
292864562Sgshapiro#  else /* NO_GETSERVBYNAME */
292964562Sgshapiro		sp = getservbyname("auth", "tcp");
293064562Sgshapiro		if (sp != NULL)
293164562Sgshapiro			RealHostAddr.sin6.sin6_port = sp->s_port;
293264562Sgshapiro		else
293364562Sgshapiro			RealHostAddr.sin6.sin6_port = htons(113);
293464562Sgshapiro		break;
293564562Sgshapiro#  endif /* NO_GETSERVBYNAME */
293664562Sgshapiro# endif /* NETINET6 */
293764562Sgshapiro	  default:
293864562Sgshapiro		/* no ident info */
293964562Sgshapiro		goto noident;
294064562Sgshapiro	}
294164562Sgshapiro
294238032Speter	s = -1;
294338032Speter	if (setjmp(CtxAuthTimeout) != 0)
294438032Speter	{
294538032Speter		if (s >= 0)
294638032Speter			(void) close(s);
294738032Speter		goto noident;
294838032Speter	}
294938032Speter
295038032Speter	/* put a timeout around the whole thing */
295138032Speter	ev = setevent(TimeOuts.to_ident, authtimeout, 0);
295238032Speter
295364562Sgshapiro
295438032Speter	/* connect to foreign IDENT server using same address as SMTP socket */
295564562Sgshapiro	s = socket(la.sa.sa_family, SOCK_STREAM, 0);
295638032Speter	if (s < 0)
295738032Speter	{
295838032Speter		clrevent(ev);
295938032Speter		goto noident;
296038032Speter	}
296164562Sgshapiro	if (bind(s, &la.sa, lalen) < 0 ||
296264562Sgshapiro	    connect(s, &RealHostAddr.sa, lalen) < 0)
296338032Speter	{
296438032Speter		goto closeident;
296538032Speter	}
296638032Speter
296738032Speter	if (tTd(9, 10))
296864562Sgshapiro		dprintf("getauthinfo: sent %s", ibuf);
296938032Speter
297038032Speter	/* send query */
297138032Speter	if (write(s, ibuf, strlen(ibuf)) < 0)
297238032Speter		goto closeident;
297338032Speter
297438032Speter	/* get result */
297538032Speter	p = &ibuf[0];
297638032Speter	nleft = sizeof ibuf - 1;
297738032Speter	while ((i = read(s, p, nleft)) > 0)
297838032Speter	{
297938032Speter		p += i;
298038032Speter		nleft -= i;
298138032Speter		*p = '\0';
298238032Speter		if (strchr(ibuf, '\n') != NULL)
298338032Speter			break;
298438032Speter	}
298538032Speter	(void) close(s);
298638032Speter	clrevent(ev);
298738032Speter	if (i < 0 || p == &ibuf[0])
298838032Speter		goto noident;
298938032Speter
299038032Speter	if (*--p == '\n' && *--p == '\r')
299138032Speter		p--;
299238032Speter	*++p = '\0';
299338032Speter
299438032Speter	if (tTd(9, 3))
299564562Sgshapiro		dprintf("getauthinfo:  got %s\n", ibuf);
299638032Speter
299738032Speter	/* parse result */
299838032Speter	p = strchr(ibuf, ':');
299938032Speter	if (p == NULL)
300038032Speter	{
300138032Speter		/* malformed response */
300238032Speter		goto noident;
300338032Speter	}
300438032Speter	while (isascii(*++p) && isspace(*p))
300538032Speter		continue;
300638032Speter	if (strncasecmp(p, "userid", 6) != 0)
300738032Speter	{
300838032Speter		/* presumably an error string */
300938032Speter		goto noident;
301038032Speter	}
301138032Speter	p += 6;
301238032Speter	while (isascii(*p) && isspace(*p))
301338032Speter		p++;
301438032Speter	if (*p++ != ':')
301538032Speter	{
301638032Speter		/* either useridxx or malformed response */
301738032Speter		goto noident;
301838032Speter	}
301938032Speter
302038032Speter	/* p now points to the OSTYPE field */
302138032Speter	while (isascii(*p) && isspace(*p))
302238032Speter		p++;
302338032Speter	ostype = p;
302438032Speter	p = strchr(p, ':');
302538032Speter	if (p == NULL)
302638032Speter	{
302738032Speter		/* malformed response */
302838032Speter		goto noident;
302938032Speter	}
303038032Speter	else
303138032Speter	{
303238032Speter		char *charset;
303338032Speter
303438032Speter		*p = '\0';
303538032Speter		charset = strchr(ostype, ',');
303638032Speter		if (charset != NULL)
303738032Speter			*charset = '\0';
303838032Speter	}
303938032Speter
304038032Speter	/* 1413 says don't do this -- but it's broken otherwise */
304138032Speter	while (isascii(*++p) && isspace(*p))
304238032Speter		continue;
304338032Speter
304438032Speter	/* p now points to the authenticated name -- copy carefully */
304538032Speter	if (strncasecmp(ostype, "other", 5) == 0 &&
304638032Speter	    (ostype[5] == ' ' || ostype[5] == '\0'))
304738032Speter	{
304838032Speter		snprintf(hbuf, sizeof hbuf, "IDENT:");
304938032Speter		cleanstrcpy(&hbuf[6], p, MAXNAME);
305038032Speter	}
305138032Speter	else
305238032Speter		cleanstrcpy(hbuf, p, MAXNAME);
305338032Speter	i = strlen(hbuf);
305438032Speter	snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
305538032Speter		 RealHostName == NULL ? "localhost" : RealHostName);
305638032Speter	goto postident;
305738032Speter
305838032Spetercloseident:
305938032Speter	(void) close(s);
306038032Speter	clrevent(ev);
306138032Speter
306238032Speternoident:
306364562Sgshapiro	/* put back the original incoming port */
306464562Sgshapiro	switch (RealHostAddr.sa.sa_family)
306564562Sgshapiro	{
306664562Sgshapiro# if NETINET
306764562Sgshapiro	  case AF_INET:
306864562Sgshapiro		if (port > 0)
306964562Sgshapiro			RealHostAddr.sin.sin_port = port;
307064562Sgshapiro		break;
307164562Sgshapiro# endif /* NETINET */
307264562Sgshapiro
307364562Sgshapiro# if NETINET6
307464562Sgshapiro	  case AF_INET6:
307564562Sgshapiro		if (port > 0)
307664562Sgshapiro			RealHostAddr.sin6.sin6_port = port;
307764562Sgshapiro		break;
307864562Sgshapiro# endif /* NETINET6 */
307964562Sgshapiro	}
308064562Sgshapiro
308138032Speter	if (RealHostName == NULL)
308238032Speter	{
308338032Speter		if (tTd(9, 1))
308464562Sgshapiro			dprintf("getauthinfo: NULL\n");
308538032Speter		return NULL;
308638032Speter	}
308738032Speter	snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
308838032Speter
308938032Speterpostident:
309064562Sgshapiro# if IP_SRCROUTE
309164562Sgshapiro#  ifndef GET_IPOPT_DST
309264562Sgshapiro#   define GET_IPOPT_DST(dst)	(dst)
309364562Sgshapiro#  endif /* ! GET_IPOPT_DST */
309438032Speter	/*
309538032Speter	**  Extract IP source routing information.
309638032Speter	**
309738032Speter	**	Format of output for a connection from site a through b
309838032Speter	**	through c to d:
309938032Speter	**		loose:      @site-c@site-b:site-a
310038032Speter	**		strict:	   !@site-c@site-b:site-a
310138032Speter	**
310238032Speter	**	o - pointer within ipopt_list structure.
310338032Speter	**	q - pointer within ls/ss rr route data
310438032Speter	**	p - pointer to hbuf
310538032Speter	*/
310638032Speter
310738032Speter	if (RealHostAddr.sa.sa_family == AF_INET)
310838032Speter	{
310938032Speter		SOCKOPT_LEN_T ipoptlen;
311038032Speter		int j;
311138032Speter		u_char *q;
311238032Speter		u_char *o;
311338032Speter		int l;
311464562Sgshapiro		struct IPOPTION ipopt;
311538032Speter
311638032Speter		ipoptlen = sizeof ipopt;
311738032Speter		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
311838032Speter			       (char *) &ipopt, &ipoptlen) < 0)
311938032Speter			goto noipsr;
312038032Speter		if (ipoptlen == 0)
312138032Speter			goto noipsr;
312264562Sgshapiro		o = (u_char *) ipopt.IP_LIST;
312338032Speter		while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
312438032Speter		{
312538032Speter			switch (*o)
312638032Speter			{
312764562Sgshapiro			  case IPOPT_EOL:
312838032Speter				o = NULL;
312938032Speter				break;
313038032Speter
313138032Speter			  case IPOPT_NOP:
313238032Speter				o++;
313338032Speter				break;
313438032Speter
313538032Speter			  case IPOPT_SSRR:
313638032Speter			  case IPOPT_LSRR:
313738032Speter				/*
313838032Speter				**  Source routing.
313938032Speter				**	o[0] is the option type (loose/strict).
314038032Speter				**	o[1] is the length of this option,
314138032Speter				**		including option type and
314238032Speter				**		length.
314338032Speter				**	o[2] is the pointer into the route
314438032Speter				**		data.
314538032Speter				**	o[3] begins the route data.
314638032Speter				*/
314738032Speter
314838032Speter				p = &hbuf[strlen(hbuf)];
314938032Speter				l = sizeof hbuf - (hbuf - p) - 6;
315038032Speter				snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
315138032Speter				    *o == IPOPT_SSRR ? "!" : "",
315238032Speter				    l > 240 ? 120 : l / 2,
315364562Sgshapiro				    inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
315438032Speter				i = strlen(p);
315538032Speter				p += i;
315638032Speter				l -= strlen(p);
315738032Speter
315838032Speter				j = o[1] / sizeof(struct in_addr) - 1;
315938032Speter
316038032Speter				/* q skips length and router pointer to data */
316138032Speter				q = &o[3];
316238032Speter				for ( ; j >= 0; j--)
316338032Speter				{
316464562Sgshapiro					struct in_addr addr;
316564562Sgshapiro
316638032Speter					memcpy(&addr, q, sizeof(addr));
316738032Speter					snprintf(p, SPACELEFT(hbuf, p),
316864562Sgshapiro						 "%c%.*s",
316964562Sgshapiro						 j != 0 ? '@' : ':',
317064562Sgshapiro						 l > 240 ? 120 :
317164562Sgshapiro						 j == 0 ? l : l / 2,
317264562Sgshapiro						 inet_ntoa(addr));
317338032Speter					i = strlen(p);
317438032Speter					p += i;
317538032Speter					l -= i + 1;
317664562Sgshapiro					q += sizeof(struct in_addr);
317738032Speter				}
317838032Speter				o += o[1];
317938032Speter				break;
318038032Speter
318138032Speter			  default:
318238032Speter				/* Skip over option */
318338032Speter				o += o[1];
318438032Speter				break;
318538032Speter			}
318638032Speter		}
318738032Speter		snprintf(p, SPACELEFT(hbuf, p), "]");
318838032Speter		goto postipsr;
318938032Speter	}
319038032Speter
319138032Speternoipsr:
319264562Sgshapiro# endif /* IP_SRCROUTE */
319338032Speter	if (RealHostName != NULL && RealHostName[0] != '[')
319438032Speter	{
319538032Speter		p = &hbuf[strlen(hbuf)];
319638032Speter		(void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
319738032Speter			anynet_ntoa(&RealHostAddr));
319838032Speter	}
319938032Speter	if (*may_be_forged)
320038032Speter	{
320138032Speter		p = &hbuf[strlen(hbuf)];
320238032Speter		(void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
320338032Speter	}
320438032Speter
320564562Sgshapiro# if IP_SRCROUTE
320638032Speterpostipsr:
320764562Sgshapiro# endif /* IP_SRCROUTE */
320838032Speter	if (tTd(9, 1))
320964562Sgshapiro		dprintf("getauthinfo: %s\n", hbuf);
321064562Sgshapiro
321164562Sgshapiro	/* put back the original incoming port */
321264562Sgshapiro	switch (RealHostAddr.sa.sa_family)
321364562Sgshapiro	{
321464562Sgshapiro# if NETINET
321564562Sgshapiro	  case AF_INET:
321664562Sgshapiro		if (port > 0)
321764562Sgshapiro			RealHostAddr.sin.sin_port = port;
321864562Sgshapiro		break;
321964562Sgshapiro# endif /* NETINET */
322064562Sgshapiro
322164562Sgshapiro# if NETINET6
322264562Sgshapiro	  case AF_INET6:
322364562Sgshapiro		if (port > 0)
322464562Sgshapiro			RealHostAddr.sin6.sin6_port = port;
322564562Sgshapiro		break;
322664562Sgshapiro# endif /* NETINET6 */
322764562Sgshapiro	}
322864562Sgshapiro
322938032Speter	return hbuf;
323038032Speter}
323138032Speter/*
323238032Speter**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
323338032Speter**
323438032Speter**	Parameters:
323538032Speter**		map -- a pointer to this map.
323638032Speter**		name -- the (presumably unqualified) hostname.
323738032Speter**		av -- unused -- for compatibility with other mapping
323838032Speter**			functions.
323938032Speter**		statp -- an exit status (out parameter) -- set to
324038032Speter**			EX_TEMPFAIL if the name server is unavailable.
324138032Speter**
324238032Speter**	Returns:
324338032Speter**		The mapping, if found.
324438032Speter**		NULL if no mapping found.
324538032Speter**
324638032Speter**	Side Effects:
324738032Speter**		Looks up the host specified in hbuf.  If it is not
324838032Speter**		the canonical name for that host, return the canonical
324938032Speter**		name (unless MF_MATCHONLY is set, which will cause the
325038032Speter**		status only to be returned).
325138032Speter*/
325238032Speter
325338032Speterchar *
325438032Speterhost_map_lookup(map, name, av, statp)
325538032Speter	MAP *map;
325638032Speter	char *name;
325738032Speter	char **av;
325838032Speter	int *statp;
325938032Speter{
326038032Speter	register struct hostent *hp;
326164562Sgshapiro# if NETINET
326238032Speter	struct in_addr in_addr;
326364562Sgshapiro# endif /* NETINET */
326464562Sgshapiro# if NETINET6
326564562Sgshapiro	struct in6_addr in6_addr;
326664562Sgshapiro# endif /* NETINET6 */
326764562Sgshapiro	char *cp, *ans = NULL;
326838032Speter	register STAB *s;
326938032Speter	char hbuf[MAXNAME + 1];
327038032Speter
327138032Speter	/*
327238032Speter	**  See if we have already looked up this name.  If so, just
327338032Speter	**  return it.
327438032Speter	*/
327538032Speter
327638032Speter	s = stab(name, ST_NAMECANON, ST_ENTER);
327738032Speter	if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
327838032Speter	{
327938032Speter		if (tTd(9, 1))
328064562Sgshapiro			dprintf("host_map_lookup(%s) => CACHE %s\n",
328164562Sgshapiro				name,
328264562Sgshapiro				s->s_namecanon.nc_cname == NULL
328338032Speter					? "NULL"
328438032Speter					: s->s_namecanon.nc_cname);
328538032Speter		errno = s->s_namecanon.nc_errno;
328664562Sgshapiro# if NAMED_BIND
328773188Sgshapiro		SM_SET_H_ERRNO(s->s_namecanon.nc_herrno);
328864562Sgshapiro# endif /* NAMED_BIND */
328938032Speter		*statp = s->s_namecanon.nc_stat;
329038032Speter		if (*statp == EX_TEMPFAIL)
329138032Speter		{
329238032Speter			CurEnv->e_status = "4.4.3";
329338032Speter			message("851 %s: Name server timeout",
329438032Speter				shortenstring(name, 33));
329538032Speter		}
329638032Speter		if (*statp != EX_OK)
329738032Speter			return NULL;
329838032Speter		if (s->s_namecanon.nc_cname == NULL)
329938032Speter		{
330038032Speter			syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
330164562Sgshapiro			       name,
330264562Sgshapiro			       s->s_namecanon.nc_errno,
330364562Sgshapiro			       s->s_namecanon.nc_herrno);
330438032Speter			return NULL;
330538032Speter		}
330638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
330738032Speter			cp = map_rewrite(map, name, strlen(name), NULL);
330838032Speter		else
330938032Speter			cp = map_rewrite(map,
331038032Speter					 s->s_namecanon.nc_cname,
331138032Speter					 strlen(s->s_namecanon.nc_cname),
331238032Speter					 av);
331338032Speter		return cp;
331438032Speter	}
331538032Speter
331638032Speter	/*
331738032Speter	**  If we are running without a regular network connection (usually
331838032Speter	**  dial-on-demand) and we are just queueing, we want to avoid DNS
331938032Speter	**  lookups because those could try to connect to a server.
332038032Speter	*/
332138032Speter
332264562Sgshapiro	if (CurEnv->e_sendmode == SM_DEFER &&
332364562Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
332438032Speter	{
332538032Speter		if (tTd(9, 1))
332664562Sgshapiro			dprintf("host_map_lookup(%s) => DEFERRED\n", name);
332738032Speter		*statp = EX_TEMPFAIL;
332838032Speter		return NULL;
332938032Speter	}
333038032Speter
333138032Speter	/*
333238032Speter	**  If first character is a bracket, then it is an address
333338032Speter	**  lookup.  Address is copied into a temporary buffer to
333438032Speter	**  strip the brackets and to preserve name if address is
333538032Speter	**  unknown.
333638032Speter	*/
333738032Speter
333864562Sgshapiro	if (tTd(9, 1))
333964562Sgshapiro		dprintf("host_map_lookup(%s) => ", name);
334038032Speter	if (*name != '[')
334138032Speter	{
334238032Speter		snprintf(hbuf, sizeof hbuf, "%s", name);
334338032Speter		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
334464562Sgshapiro			ans = hbuf;
334564562Sgshapiro	}
334664562Sgshapiro	else
334764562Sgshapiro	{
334864562Sgshapiro		if ((cp = strchr(name, ']')) == NULL)
334971345Sgshapiro		{
335071345Sgshapiro			if (tTd(9, 1))
335171345Sgshapiro				dprintf("FAILED\n");
335264562Sgshapiro			return NULL;
335371345Sgshapiro		}
335464562Sgshapiro		*cp = '\0';
335564562Sgshapiro
335664562Sgshapiro		hp = NULL;
335764562Sgshapiro# if NETINET
335864562Sgshapiro		if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
335964562Sgshapiro			hp = sm_gethostbyaddr((char *)&in_addr,
336064562Sgshapiro					      INADDRSZ, AF_INET);
336164562Sgshapiro# endif /* NETINET */
336264562Sgshapiro# if NETINET6
336364562Sgshapiro		if (hp == NULL &&
336464562Sgshapiro		    inet_pton(AF_INET6, &name[1], &in6_addr) == 1)
336564562Sgshapiro			hp = sm_gethostbyaddr((char *)&in6_addr,
336664562Sgshapiro					      IN6ADDRSZ, AF_INET6);
336764562Sgshapiro# endif /* NETINET6 */
336864562Sgshapiro		*cp = ']';
336964562Sgshapiro
337064562Sgshapiro		if (hp != NULL)
337138032Speter		{
337264562Sgshapiro			/* found a match -- copy out */
337364562Sgshapiro			ans = denlstring((char *) hp->h_name, TRUE, TRUE);
337471345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
337571345Sgshapiro			freehostent(hp);
337671345Sgshapiro			hp = NULL;
337771345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
337838032Speter		}
337964562Sgshapiro	}
338038032Speter
338164562Sgshapiro	s->s_namecanon.nc_flags |= NCF_VALID;	/* will be soon */
338238032Speter
338364562Sgshapiro	/* Found an answer */
338464562Sgshapiro	if (ans != NULL)
338564562Sgshapiro	{
338664562Sgshapiro		s->s_namecanon.nc_stat = *statp = EX_OK;
338764562Sgshapiro		s->s_namecanon.nc_cname = newstr(ans);
338864562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
338964562Sgshapiro			cp = map_rewrite(map, name, strlen(name), NULL);
339064562Sgshapiro		else
339164562Sgshapiro			cp = map_rewrite(map, ans, strlen(ans), av);
339271345Sgshapiro		if (tTd(9, 1))
339371345Sgshapiro			dprintf("FOUND %s\n", ans);
339464562Sgshapiro		return cp;
339538032Speter	}
339638032Speter
339764562Sgshapiro
339864562Sgshapiro	/* No match found */
339938032Speter	s->s_namecanon.nc_errno = errno;
340064562Sgshapiro# if NAMED_BIND
340138032Speter	s->s_namecanon.nc_herrno = h_errno;
340264562Sgshapiro	if (tTd(9, 1))
340364562Sgshapiro		dprintf("FAIL (%d)\n", h_errno);
340464562Sgshapiro	switch (h_errno)
340538032Speter	{
340664562Sgshapiro	  case TRY_AGAIN:
340764562Sgshapiro		if (UseNameServer)
340864562Sgshapiro		{
340964562Sgshapiro			CurEnv->e_status = "4.4.3";
341064562Sgshapiro			message("851 %s: Name server timeout",
341164562Sgshapiro				shortenstring(name, 33));
341264562Sgshapiro		}
341364562Sgshapiro		*statp = EX_TEMPFAIL;
341464562Sgshapiro		break;
341564562Sgshapiro
341664562Sgshapiro	  case HOST_NOT_FOUND:
341764562Sgshapiro	  case NO_DATA:
341864562Sgshapiro		*statp = EX_NOHOST;
341964562Sgshapiro		break;
342064562Sgshapiro
342164562Sgshapiro	  case NO_RECOVERY:
342264562Sgshapiro		*statp = EX_SOFTWARE;
342364562Sgshapiro		break;
342464562Sgshapiro
342564562Sgshapiro	  default:
342664562Sgshapiro		*statp = EX_UNAVAILABLE;
342764562Sgshapiro		break;
342838032Speter	}
342964562Sgshapiro# else /* NAMED_BIND */
343064562Sgshapiro	if (tTd(9, 1))
343164562Sgshapiro		dprintf("FAIL\n");
343264562Sgshapiro	*statp = EX_NOHOST;
343364562Sgshapiro# endif /* NAMED_BIND */
343464562Sgshapiro	s->s_namecanon.nc_stat = *statp;
343564562Sgshapiro	return NULL;
343638032Speter}
343764562Sgshapiro#else /* DAEMON */
343838032Speter/* code for systems without sophisticated networking */
343938032Speter
344038032Speter/*
344138032Speter**  MYHOSTNAME -- stub version for case of no daemon code.
344238032Speter**
344338032Speter**	Can't convert to upper case here because might be a UUCP name.
344438032Speter**
344538032Speter**	Mark, you can change this to be anything you want......
344638032Speter*/
344738032Speter
344838032Speterchar **
344938032Spetermyhostname(hostbuf, size)
345038032Speter	char hostbuf[];
345138032Speter	int size;
345238032Speter{
345338032Speter	register FILE *f;
345438032Speter
345538032Speter	hostbuf[0] = '\0';
345638032Speter	f = fopen("/usr/include/whoami", "r");
345738032Speter	if (f != NULL)
345838032Speter	{
345938032Speter		(void) fgets(hostbuf, size, f);
346038032Speter		fixcrlf(hostbuf, TRUE);
346138032Speter		(void) fclose(f);
346238032Speter	}
346373188Sgshapiro	if (hostbuf[0] == '\0')
346473188Sgshapiro		(void) strlcpy(hostbuf, "localhost", size);
346564562Sgshapiro	return NULL;
346638032Speter}
346738032Speter/*
346864562Sgshapiro**  GETAUTHINFO -- get the real host name associated with a file descriptor
346938032Speter**
347038032Speter**	Parameters:
347138032Speter**		fd -- the descriptor
347238032Speter**		may_be_forged -- an outage that is set to TRUE if the
347338032Speter**			forward lookup of RealHostName does not match
347438032Speter**			RealHostAddr; set to FALSE if they do match.
347538032Speter**
347638032Speter**	Returns:
347738032Speter**		The host name associated with this descriptor, if it can
347838032Speter**			be determined.
347938032Speter**		NULL otherwise.
348038032Speter**
348138032Speter**	Side Effects:
348238032Speter**		none
348338032Speter*/
348438032Speter
348538032Speterchar *
348638032Spetergetauthinfo(fd, may_be_forged)
348738032Speter	int fd;
348838032Speter	bool *may_be_forged;
348938032Speter{
349038032Speter	*may_be_forged = FALSE;
349138032Speter	return NULL;
349238032Speter}
349338032Speter/*
349464562Sgshapiro**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
349538032Speter**
349638032Speter**	Parameters:
349738032Speter**		map -- a pointer to the database map.
349838032Speter**		name -- a buffer containing a hostname.
349938032Speter**		avp -- a pointer to a (cf file defined) argument vector.
350038032Speter**		statp -- an exit status (out parameter).
350138032Speter**
350238032Speter**	Returns:
350338032Speter**		mapped host name
350438032Speter**		FALSE otherwise.
350538032Speter**
350638032Speter**	Side Effects:
350738032Speter**		Looks up the host specified in name.  If it is not
350838032Speter**		the canonical name for that host, replace it with
350938032Speter**		the canonical name.  If the name is unknown, or it
351038032Speter**		is already the canonical name, leave it unchanged.
351138032Speter*/
351238032Speter
351338032Speter/*ARGSUSED*/
351438032Speterchar *
351538032Speterhost_map_lookup(map, name, avp, statp)
351638032Speter	MAP *map;
351738032Speter	char *name;
351838032Speter	char **avp;
351938032Speter	char *statp;
352038032Speter{
352164562Sgshapiro	register struct hostent *hp = NULL;
352238032Speter	char *cp;
352338032Speter
352464562Sgshapiro	hp = sm_gethostbyname(name, InetMode);
352564562Sgshapiro	if (hp == NULL && InetMode != AF_INET)
352664562Sgshapiro		hp = sm_gethostbyname(name, AF_INET);
352738032Speter	if (hp == NULL)
352838032Speter	{
352964562Sgshapiro# if NAMED_BIND
353064562Sgshapiro		if (tTd(9, 1))
353164562Sgshapiro			dprintf("FAIL (%d)\n", h_errno);
353264562Sgshapiro		switch (h_errno)
353364562Sgshapiro		{
353464562Sgshapiro		  case TRY_AGAIN:
353564562Sgshapiro			if (UseNameServer)
353664562Sgshapiro			{
353764562Sgshapiro				CurEnv->e_status = "4.4.3";
353864562Sgshapiro				message("851 %s: Name server timeout",
353964562Sgshapiro					shortenstring(name, 33));
354064562Sgshapiro			}
354164562Sgshapiro			*statp = EX_TEMPFAIL;
354264562Sgshapiro			break;
354364562Sgshapiro
354464562Sgshapiro		  case HOST_NOT_FOUND:
354564562Sgshapiro		  case NO_DATA:
354664562Sgshapiro			*statp = EX_NOHOST;
354764562Sgshapiro			break;
354864562Sgshapiro
354964562Sgshapiro		  case NO_RECOVERY:
355064562Sgshapiro			*statp = EX_SOFTWARE;
355164562Sgshapiro			break;
355264562Sgshapiro
355364562Sgshapiro		  default:
355464562Sgshapiro			*statp = EX_UNAVAILABLE;
355564562Sgshapiro			break;
355664562Sgshapiro		}
355764562Sgshapiro#else /* NAMED_BIND */
355838032Speter		*statp = EX_NOHOST;
355964562Sgshapiro#endif /* NAMED_BIND */
356038032Speter		return NULL;
356138032Speter	}
356238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
356338032Speter		cp = map_rewrite(map, name, strlen(name), NULL);
356438032Speter	else
356538032Speter		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
356671345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
356771345Sgshapiro	freehostent(hp);
356871345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
356938032Speter	return cp;
357038032Speter}
357138032Speter
357238032Speter#endif /* DAEMON */
357338032Speter/*
357438032Speter**  HOST_MAP_INIT -- initialize host class structures
357538032Speter*/
357638032Speter
357738032Speterbool
357838032Speterhost_map_init(map, args)
357938032Speter	MAP *map;
358038032Speter	char *args;
358138032Speter{
358238032Speter	register char *p = args;
358338032Speter
358438032Speter	for (;;)
358538032Speter	{
358638032Speter		while (isascii(*p) && isspace(*p))
358738032Speter			p++;
358838032Speter		if (*p != '-')
358938032Speter			break;
359038032Speter		switch (*++p)
359138032Speter		{
359238032Speter		  case 'a':
359338032Speter			map->map_app = ++p;
359438032Speter			break;
359538032Speter
359638032Speter		  case 'T':
359738032Speter			map->map_tapp = ++p;
359838032Speter			break;
359938032Speter
360038032Speter		  case 'm':
360138032Speter			map->map_mflags |= MF_MATCHONLY;
360238032Speter			break;
360338032Speter
360438032Speter		  case 't':
360538032Speter			map->map_mflags |= MF_NODEFER;
360638032Speter			break;
360764562Sgshapiro
360864562Sgshapiro		  case 'S':	/* only for consistency */
360964562Sgshapiro			map->map_spacesub = *++p;
361064562Sgshapiro			break;
361164562Sgshapiro
361264562Sgshapiro		  case 'D':
361364562Sgshapiro			map->map_mflags |= MF_DEFER;
361464562Sgshapiro			break;
361538032Speter		}
361638032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
361738032Speter			p++;
361838032Speter		if (*p != '\0')
361938032Speter			*p++ = '\0';
362038032Speter	}
362138032Speter	if (map->map_app != NULL)
362238032Speter		map->map_app = newstr(map->map_app);
362338032Speter	if (map->map_tapp != NULL)
362438032Speter		map->map_tapp = newstr(map->map_tapp);
362538032Speter	return TRUE;
362638032Speter}
362764562Sgshapiro
362864562Sgshapiro#if NETINET6
362964562Sgshapiro/*
363064562Sgshapiro**  ANYNET_NTOP -- convert an IPv6 network address to printable form.
363164562Sgshapiro**
363264562Sgshapiro**	Parameters:
363364562Sgshapiro**		s6a -- a pointer to an in6_addr structure.
363464562Sgshapiro**		dst -- buffer to store result in
363564562Sgshapiro**		dst_len -- size of dst buffer
363664562Sgshapiro**
363764562Sgshapiro**	Returns:
363864562Sgshapiro**		A printable version of that structure.
363964562Sgshapiro*/
364064562Sgshapirochar *
364164562Sgshapiroanynet_ntop(s6a, dst, dst_len)
364264562Sgshapiro	struct in6_addr *s6a;
364364562Sgshapiro	char *dst;
364464562Sgshapiro	size_t dst_len;
364564562Sgshapiro{
364664562Sgshapiro	register char *ap;
364764562Sgshapiro
364864562Sgshapiro	if (IN6_IS_ADDR_V4MAPPED(s6a))
364964562Sgshapiro		ap = (char *) inet_ntop(AF_INET,
365064562Sgshapiro					&s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
365164562Sgshapiro					dst, dst_len);
365264562Sgshapiro	else
365364562Sgshapiro		ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
365464562Sgshapiro	return ap;
365564562Sgshapiro}
365664562Sgshapiro#endif /* NETINET6 */
365738032Speter/*
365838032Speter**  ANYNET_NTOA -- convert a network address to printable form.
365938032Speter**
366038032Speter**	Parameters:
366138032Speter**		sap -- a pointer to a sockaddr structure.
366238032Speter**
366338032Speter**	Returns:
366438032Speter**		A printable version of that sockaddr.
366538032Speter*/
366638032Speter
366738032Speter#ifdef USE_SOCK_STREAM
366838032Speter
366964562Sgshapiro# if NETLINK
367064562Sgshapiro#  include <net/if_dl.h>
367164562Sgshapiro# endif /* NETLINK */
367238032Speter
367338032Speterchar *
367438032Speteranynet_ntoa(sap)
367538032Speter	register SOCKADDR *sap;
367638032Speter{
367738032Speter	register char *bp;
367838032Speter	register char *ap;
367938032Speter	int l;
368038032Speter	static char buf[100];
368138032Speter
368238032Speter	/* check for null/zero family */
368338032Speter	if (sap == NULL)
368438032Speter		return "NULLADDR";
368538032Speter	if (sap->sa.sa_family == 0)
368638032Speter		return "0";
368738032Speter
368838032Speter	switch (sap->sa.sa_family)
368938032Speter	{
369064562Sgshapiro# if NETUNIX
369138032Speter	  case AF_UNIX:
369264562Sgshapiro		if (sap->sunix.sun_path[0] != '\0')
369364562Sgshapiro			snprintf(buf, sizeof buf, "[UNIX: %.64s]",
369438032Speter				sap->sunix.sun_path);
369564562Sgshapiro		else
369664562Sgshapiro			snprintf(buf, sizeof buf, "[UNIX: localhost]");
369738032Speter		return buf;
369864562Sgshapiro# endif /* NETUNIX */
369938032Speter
370064562Sgshapiro# if NETINET
370138032Speter	  case AF_INET:
370264562Sgshapiro		return (char *) inet_ntoa(sap->sin.sin_addr);
370364562Sgshapiro# endif /* NETINET */
370438032Speter
370564562Sgshapiro# if NETINET6
370664562Sgshapiro	  case AF_INET6:
370764562Sgshapiro		ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf);
370864562Sgshapiro		if (ap != NULL)
370964562Sgshapiro			return ap;
371064562Sgshapiro		break;
371164562Sgshapiro# endif /* NETINET6 */
371264562Sgshapiro
371364562Sgshapiro# if NETLINK
371438032Speter	  case AF_LINK:
371538032Speter		snprintf(buf, sizeof buf, "[LINK: %s]",
371638032Speter			link_ntoa((struct sockaddr_dl *) &sap->sa));
371738032Speter		return buf;
371864562Sgshapiro# endif /* NETLINK */
371938032Speter	  default:
372038032Speter		/* this case is needed when nothing is #defined */
372138032Speter		/* in order to keep the switch syntactically correct */
372238032Speter		break;
372338032Speter	}
372438032Speter
372538032Speter	/* unknown family -- just dump bytes */
372638032Speter	(void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
372738032Speter	bp = &buf[strlen(buf)];
372838032Speter	ap = sap->sa.sa_data;
372938032Speter	for (l = sizeof sap->sa.sa_data; --l >= 0; )
373038032Speter	{
373138032Speter		(void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
373238032Speter		bp += 3;
373338032Speter	}
373438032Speter	*--bp = '\0';
373538032Speter	return buf;
373638032Speter}
373738032Speter/*
373838032Speter**  HOSTNAMEBYANYADDR -- return name of host based on address
373938032Speter**
374038032Speter**	Parameters:
374138032Speter**		sap -- SOCKADDR pointer
374238032Speter**
374338032Speter**	Returns:
374438032Speter**		text representation of host name.
374538032Speter**
374638032Speter**	Side Effects:
374738032Speter**		none.
374838032Speter*/
374938032Speter
375038032Speterchar *
375138032Speterhostnamebyanyaddr(sap)
375238032Speter	register SOCKADDR *sap;
375338032Speter{
375438032Speter	register struct hostent *hp;
375564562Sgshapiro# if NAMED_BIND
375638032Speter	int saveretry;
375764562Sgshapiro# endif /* NAMED_BIND */
375864562Sgshapiro# if NETINET6
375964562Sgshapiro	struct in6_addr in6_addr;
376064562Sgshapiro# endif /* NETINET6 */
376138032Speter
376264562Sgshapiro# if NAMED_BIND
376338032Speter	/* shorten name server timeout to avoid higher level timeouts */
376438032Speter	saveretry = _res.retry;
376564562Sgshapiro	if (_res.retry * _res.retrans > 20)
376664562Sgshapiro		_res.retry = 20 / _res.retrans;
376764562Sgshapiro# endif /* NAMED_BIND */
376838032Speter
376938032Speter	switch (sap->sa.sa_family)
377038032Speter	{
377164562Sgshapiro# if NETINET
377238032Speter	  case AF_INET:
377338032Speter		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
377438032Speter			INADDRSZ,
377538032Speter			AF_INET);
377638032Speter		break;
377764562Sgshapiro# endif /* NETINET */
377838032Speter
377964562Sgshapiro# if NETINET6
378064562Sgshapiro	  case AF_INET6:
378164562Sgshapiro		hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
378264562Sgshapiro				      IN6ADDRSZ,
378364562Sgshapiro				      AF_INET6);
378464562Sgshapiro		break;
378564562Sgshapiro# endif /* NETINET6 */
378664562Sgshapiro
378764562Sgshapiro# if NETISO
378838032Speter	  case AF_ISO:
378938032Speter		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
379038032Speter			sizeof sap->siso.siso_addr,
379138032Speter			AF_ISO);
379238032Speter		break;
379364562Sgshapiro# endif /* NETISO */
379438032Speter
379564562Sgshapiro# if NETUNIX
379638032Speter	  case AF_UNIX:
379738032Speter		hp = NULL;
379838032Speter		break;
379964562Sgshapiro# endif /* NETUNIX */
380038032Speter
380138032Speter	  default:
380238032Speter		hp = sm_gethostbyaddr(sap->sa.sa_data,
380338032Speter			   sizeof sap->sa.sa_data,
380438032Speter			   sap->sa.sa_family);
380538032Speter		break;
380638032Speter	}
380738032Speter
380864562Sgshapiro# if NAMED_BIND
380938032Speter	_res.retry = saveretry;
381064562Sgshapiro# endif /* NAMED_BIND */
381138032Speter
381264562Sgshapiro# if NETINET || NETINET6
381364562Sgshapiro	if (hp != NULL && hp->h_name[0] != '['
381464562Sgshapiro#  if NETINET6
381564562Sgshapiro	    && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1
381664562Sgshapiro#  endif /* NETINET6 */
381764562Sgshapiro#  if NETINET
381864562Sgshapiro	    && inet_addr(hp->h_name) == INADDR_NONE
381964562Sgshapiro#  endif /* NETINET */
382064562Sgshapiro	    )
382171345Sgshapiro	{
382271345Sgshapiro		char *name;
382371345Sgshapiro
382471345Sgshapiro		name = denlstring((char *) hp->h_name, TRUE, TRUE);
382571345Sgshapiro
382671345Sgshapiro#  if _FFR_FREEHOSTENT && NETINET6
382771345Sgshapiro		if (name == hp->h_name)
382871345Sgshapiro		{
382971345Sgshapiro			static char n[MAXNAME + 1];
383071345Sgshapiro
383171345Sgshapiro			/* Copy the string, hp->h_name is about to disappear */
383271345Sgshapiro			strlcpy(n, name, sizeof n);
383371345Sgshapiro			name = n;
383471345Sgshapiro		}
383571345Sgshapiro
383671345Sgshapiro		freehostent(hp);
383771345Sgshapiro#  endif /* _FFR_FREEHOSTENT && NETINET6 */
383871345Sgshapiro		return name;
383971345Sgshapiro	}
384064562Sgshapiro# endif /* NETINET || NETINET6 */
384171345Sgshapiro
384271345Sgshapiro# if _FFR_FREEHOSTENT && NETINET6
384371345Sgshapiro	if (hp != NULL)
384471345Sgshapiro	{
384571345Sgshapiro		freehostent(hp);
384671345Sgshapiro		hp = NULL;
384771345Sgshapiro	}
384871345Sgshapiro# endif /* _FFR_FREEHOSTENT && NETINET6 */
384971345Sgshapiro
385064562Sgshapiro# if NETUNIX
385164562Sgshapiro	if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
385238032Speter		return "localhost";
385364562Sgshapiro# endif /* NETUNIX */
385438032Speter	{
385538032Speter		static char buf[203];
385638032Speter
385738032Speter		(void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
385838032Speter		return buf;
385938032Speter	}
386038032Speter}
386164562Sgshapiro#endif /* USE_SOCK_STREAM */
3862