daemon.c revision 38032
138032Speter/*
238032Speter * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
438032Speter * Copyright (c) 1988, 1993
538032Speter *	The Regents of the University of California.  All rights reserved.
638032Speter *
738032Speter * By using this file, you agree to the terms and conditions set
838032Speter * forth in the LICENSE file which can be found at the top level of
938032Speter * the sendmail distribution.
1038032Speter *
1138032Speter */
1238032Speter
1338032Speter#include <errno.h>
1438032Speter#include "sendmail.h"
1538032Speter
1638032Speter#ifndef lint
1738032Speter#ifdef DAEMON
1838032Speterstatic char sccsid[] = "@(#)daemon.c	8.220 (Berkeley) 6/24/98 (with daemon mode)";
1938032Speter#else
2038032Speterstatic char sccsid[] = "@(#)daemon.c	8.220 (Berkeley) 6/24/98 (without daemon mode)";
2138032Speter#endif
2238032Speter#endif /* not lint */
2338032Speter
2438032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
2538032Speter# define USE_SOCK_STREAM	1
2638032Speter#endif
2738032Speter
2838032Speter#if DAEMON || defined(USE_SOCK_STREAM)
2938032Speter# include <arpa/inet.h>
3038032Speter# if NAMED_BIND
3138032Speter#  include <resolv.h>
3238032Speter#  ifndef NO_DATA
3338032Speter#   define NO_DATA	NO_ADDRESS
3438032Speter#  endif
3538032Speter# endif
3638032Speter#endif
3738032Speter
3838032Speter#if DAEMON
3938032Speter
4038032Speter# include <sys/time.h>
4138032Speter
4238032Speter# if IP_SRCROUTE
4338032Speter#  include <netinet/in_systm.h>
4438032Speter#  include <netinet/ip.h>
4538032Speter#  include <netinet/ip_var.h>
4638032Speter# endif
4738032Speter
4838032Speter/*
4938032Speter**  DAEMON.C -- routines to use when running as a daemon.
5038032Speter**
5138032Speter**	This entire file is highly dependent on the 4.2 BSD
5238032Speter**	interprocess communication primitives.  No attempt has
5338032Speter**	been made to make this file portable to Version 7,
5438032Speter**	Version 6, MPX files, etc.  If you should try such a
5538032Speter**	thing yourself, I recommend chucking the entire file
5638032Speter**	and starting from scratch.  Basic semantics are:
5738032Speter**
5838032Speter**	getrequests(e)
5938032Speter**		Opens a port and initiates a connection.
6038032Speter**		Returns in a child.  Must set InChannel and
6138032Speter**		OutChannel appropriately.
6238032Speter**	clrdaemon()
6338032Speter**		Close any open files associated with getting
6438032Speter**		the connection; this is used when running the queue,
6538032Speter**		etc., to avoid having extra file descriptors during
6638032Speter**		the queue run and to avoid confusing the network
6738032Speter**		code (if it cares).
6838032Speter**	makeconnection(host, port, outfile, infile, e)
6938032Speter**		Make a connection to the named host on the given
7038032Speter**		port.  Set *outfile and *infile to the files
7138032Speter**		appropriate for communication.  Returns zero on
7238032Speter**		success, else an exit status describing the
7338032Speter**		error.
7438032Speter**	host_map_lookup(map, hbuf, avp, pstat)
7538032Speter**		Convert the entry in hbuf into a canonical form.
7638032Speter*/
7738032Speter/*
7838032Speter**  GETREQUESTS -- open mail IPC port and get requests.
7938032Speter**
8038032Speter**	Parameters:
8138032Speter**		e -- the current envelope.
8238032Speter**
8338032Speter**	Returns:
8438032Speter**		none.
8538032Speter**
8638032Speter**	Side Effects:
8738032Speter**		Waits until some interesting activity occurs.  When
8838032Speter**		it does, a child is created to process it, and the
8938032Speter**		parent waits for completion.  Return from this
9038032Speter**		routine is always in the child.  The file pointers
9138032Speter**		"InChannel" and "OutChannel" should be set to point
9238032Speter**		to the communication channel.
9338032Speter*/
9438032Speter
9538032Speterint		DaemonSocket	= -1;		/* fd describing socket */
9638032SpeterSOCKADDR	DaemonAddr;			/* socket for incoming */
9738032Speterint		ListenQueueSize = 10;		/* size of listen queue */
9838032Speterint		TcpRcvBufferSize = 0;		/* size of TCP receive buffer */
9938032Speterint		TcpSndBufferSize = 0;		/* size of TCP send buffer */
10038032Speter
10138032Spetervoid
10238032Spetergetrequests(e)
10338032Speter	ENVELOPE *e;
10438032Speter{
10538032Speter	int t;
10638032Speter	bool refusingconnections = TRUE;
10738032Speter	FILE *pidf;
10838032Speter	int socksize;
10938032Speter	u_short port;
11038032Speter#if XDEBUG
11138032Speter	bool j_has_dot;
11238032Speter#endif
11338032Speter	extern void reapchild __P((int));
11438032Speter	extern int opendaemonsocket __P((bool));
11538032Speter
11638032Speter	/*
11738032Speter	**  Set up the address for the mailer.
11838032Speter	*/
11938032Speter
12038032Speter	switch (DaemonAddr.sa.sa_family)
12138032Speter	{
12238032Speter	  case AF_UNSPEC:
12338032Speter		DaemonAddr.sa.sa_family = AF_INET;
12438032Speter		/* fall through ... */
12538032Speter
12638032Speter	  case AF_INET:
12738032Speter		if (DaemonAddr.sin.sin_addr.s_addr == 0)
12838032Speter			DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
12938032Speter		port = DaemonAddr.sin.sin_port;
13038032Speter		break;
13138032Speter
13238032Speter	  default:
13338032Speter		/* unknown protocol */
13438032Speter		port = 0;
13538032Speter		break;
13638032Speter	}
13738032Speter	if (port == 0)
13838032Speter	{
13938032Speter		register struct servent *sp;
14038032Speter
14138032Speter		sp = getservbyname("smtp", "tcp");
14238032Speter		if (sp == NULL)
14338032Speter		{
14438032Speter			syserr("554 service \"smtp\" unknown");
14538032Speter			port = htons(25);
14638032Speter		}
14738032Speter		else
14838032Speter			port = sp->s_port;
14938032Speter	}
15038032Speter
15138032Speter	switch (DaemonAddr.sa.sa_family)
15238032Speter	{
15338032Speter	  case AF_INET:
15438032Speter		DaemonAddr.sin.sin_port = port;
15538032Speter		break;
15638032Speter
15738032Speter	  default:
15838032Speter		/* unknown protocol */
15938032Speter		break;
16038032Speter	}
16138032Speter
16238032Speter	/*
16338032Speter	**  Try to actually open the connection.
16438032Speter	*/
16538032Speter
16638032Speter	if (tTd(15, 1))
16738032Speter		printf("getrequests: port 0x%x\n", port);
16838032Speter
16938032Speter	/* get a socket for the SMTP connection */
17038032Speter	socksize = opendaemonsocket(TRUE);
17138032Speter
17238032Speter	(void) setsignal(SIGCHLD, reapchild);
17338032Speter
17438032Speter	/* write the pid to the log file for posterity */
17538032Speter	pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644,
17638032Speter			 SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT);
17738032Speter	if (pidf == NULL)
17838032Speter	{
17938032Speter		sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile);
18038032Speter	}
18138032Speter	else
18238032Speter	{
18338032Speter		extern char *CommandLineArgs;
18438032Speter
18538032Speter		/* write the process id on line 1 */
18638032Speter		fprintf(pidf, "%ld\n", (long) getpid());
18738032Speter
18838032Speter		/* line 2 contains all command line flags */
18938032Speter		fprintf(pidf, "%s\n", CommandLineArgs);
19038032Speter
19138032Speter		/* flush and close */
19238032Speter		fclose(pidf);
19338032Speter	}
19438032Speter
19538032Speter#if XDEBUG
19638032Speter	{
19738032Speter		char jbuf[MAXHOSTNAMELEN];
19838032Speter
19938032Speter		expand("\201j", jbuf, sizeof jbuf, e);
20038032Speter		j_has_dot = strchr(jbuf, '.') != NULL;
20138032Speter	}
20238032Speter#endif
20338032Speter
20438032Speter	if (tTd(15, 1))
20538032Speter		printf("getrequests: %d\n", DaemonSocket);
20638032Speter
20738032Speter	for (;;)
20838032Speter	{
20938032Speter		register pid_t pid;
21038032Speter		auto SOCKADDR_LEN_T lotherend;
21138032Speter		int savederrno;
21238032Speter		int pipefd[2];
21338032Speter		extern bool refuseconnections __P((int));
21438032Speter
21538032Speter		/* see if we are rejecting connections */
21638032Speter		(void) blocksignal(SIGALRM);
21738032Speter		if (refuseconnections(ntohs(port)))
21838032Speter		{
21938032Speter			if (DaemonSocket >= 0)
22038032Speter			{
22138032Speter				/* close socket so peer will fail quickly */
22238032Speter				(void) close(DaemonSocket);
22338032Speter				DaemonSocket = -1;
22438032Speter			}
22538032Speter			refusingconnections = TRUE;
22638032Speter			sleep(15);
22738032Speter			continue;
22838032Speter		}
22938032Speter
23038032Speter		/* arrange to (re)open the socket if necessary */
23138032Speter		if (refusingconnections)
23238032Speter		{
23338032Speter			(void) opendaemonsocket(FALSE);
23438032Speter			refusingconnections = FALSE;
23538032Speter		}
23638032Speter
23738032Speter#if XDEBUG
23838032Speter		/* check for disaster */
23938032Speter		{
24038032Speter			char jbuf[MAXHOSTNAMELEN];
24138032Speter			extern void dumpstate __P((char *));
24238032Speter
24338032Speter			expand("\201j", jbuf, sizeof jbuf, e);
24438032Speter			if (!wordinclass(jbuf, 'w'))
24538032Speter			{
24638032Speter				dumpstate("daemon lost $j");
24738032Speter				sm_syslog(LOG_ALERT, NOQID,
24838032Speter					"daemon process doesn't have $j in $=w; see syslog");
24938032Speter				abort();
25038032Speter			}
25138032Speter			else if (j_has_dot && strchr(jbuf, '.') == NULL)
25238032Speter			{
25338032Speter				dumpstate("daemon $j lost dot");
25438032Speter				sm_syslog(LOG_ALERT, NOQID,
25538032Speter					"daemon process $j lost dot; see syslog");
25638032Speter				abort();
25738032Speter			}
25838032Speter		}
25938032Speter#endif
26038032Speter
26138032Speter		/* wait for a connection */
26238032Speter		setproctitle("accepting connections on port %d",
26338032Speter			     ntohs(port));
26438032Speter#if 0
26538032Speter		/*
26638032Speter		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
26738032Speter		**  fix the SVr4 problem.  But it seems to have gone away,
26838032Speter		**  so is it worth doing this?
26938032Speter		*/
27038032Speter
27138032Speter		if (SetNonBlocking(DaemonSocket, FALSE) < 0)
27238032Speter			log an error here;
27338032Speter#endif
27438032Speter		(void) releasesignal(SIGALRM);
27538032Speter		for (;;)
27638032Speter		{
27738032Speter			fd_set readfds;
27838032Speter			struct timeval timeout;
27938032Speter
28038032Speter			FD_ZERO(&readfds);
28138032Speter			FD_SET(DaemonSocket, &readfds);
28238032Speter			timeout.tv_sec = 60;
28338032Speter			timeout.tv_usec = 0;
28438032Speter
28538032Speter			t = select(DaemonSocket + 1, FDSET_CAST &readfds,
28638032Speter				   NULL, NULL, &timeout);
28738032Speter			if (DoQueueRun)
28838032Speter				(void) runqueue(TRUE, FALSE);
28938032Speter			if (t <= 0 || !FD_ISSET(DaemonSocket, &readfds))
29038032Speter				continue;
29138032Speter
29238032Speter			errno = 0;
29338032Speter			lotherend = socksize;
29438032Speter			t = accept(DaemonSocket,
29538032Speter			    (struct sockaddr *)&RealHostAddr, &lotherend);
29638032Speter			if (t >= 0 || errno != EINTR)
29738032Speter				break;
29838032Speter		}
29938032Speter		savederrno = errno;
30038032Speter		(void) blocksignal(SIGALRM);
30138032Speter		if (t < 0)
30238032Speter		{
30338032Speter			errno = savederrno;
30438032Speter			syserr("getrequests: accept");
30538032Speter
30638032Speter			/* arrange to re-open the socket next time around */
30738032Speter			(void) close(DaemonSocket);
30838032Speter			DaemonSocket = -1;
30938032Speter			refusingconnections = TRUE;
31038032Speter			sleep(5);
31138032Speter			continue;
31238032Speter		}
31338032Speter
31438032Speter		/*
31538032Speter		**  Create a subprocess to process the mail.
31638032Speter		*/
31738032Speter
31838032Speter		if (tTd(15, 2))
31938032Speter			printf("getrequests: forking (fd = %d)\n", t);
32038032Speter
32138032Speter		/*
32238032Speter		**  Create a pipe to keep the child from writing to the
32338032Speter		**  socket until after the parent has closed it.  Otherwise
32438032Speter		**  the parent may hang if the child has closed it first.
32538032Speter		*/
32638032Speter
32738032Speter		if (pipe(pipefd) < 0)
32838032Speter			pipefd[0] = pipefd[1] = -1;
32938032Speter
33038032Speter		blocksignal(SIGCHLD);
33138032Speter		pid = fork();
33238032Speter		if (pid < 0)
33338032Speter		{
33438032Speter			syserr("daemon: cannot fork");
33538032Speter			if (pipefd[0] != -1)
33638032Speter			{
33738032Speter				(void) close(pipefd[0]);
33838032Speter				(void) close(pipefd[1]);
33938032Speter			}
34038032Speter			(void) releasesignal(SIGCHLD);
34138032Speter			sleep(10);
34238032Speter			(void) close(t);
34338032Speter			continue;
34438032Speter		}
34538032Speter
34638032Speter		if (pid == 0)
34738032Speter		{
34838032Speter			char *p;
34938032Speter			extern SIGFUNC_DECL intsig __P((int));
35038032Speter			FILE *inchannel, *outchannel;
35138032Speter
35238032Speter			/*
35338032Speter			**  CHILD -- return to caller.
35438032Speter			**	Collect verified idea of sending host.
35538032Speter			**	Verify calling user id if possible here.
35638032Speter			*/
35738032Speter
35838032Speter			(void) releasesignal(SIGALRM);
35938032Speter			(void) releasesignal(SIGCHLD);
36038032Speter			(void) setsignal(SIGCHLD, SIG_DFL);
36138032Speter			(void) setsignal(SIGHUP, intsig);
36238032Speter			(void) close(DaemonSocket);
36338032Speter			proc_list_clear();
36438032Speter
36538032Speter			/* don't schedule queue runs if we are told to ETRN */
36638032Speter			QueueIntvl = 0;
36738032Speter
36838032Speter			setproctitle("startup with %s",
36938032Speter				anynet_ntoa(&RealHostAddr));
37038032Speter
37138032Speter			if (pipefd[0] != -1)
37238032Speter			{
37338032Speter				auto char c;
37438032Speter
37538032Speter				/*
37638032Speter				**  Wait for the parent to close the write end
37738032Speter				**  of the pipe, which we will see as an EOF.
37838032Speter				**  This guarantees that we won't write to the
37938032Speter				**  socket until after the parent has closed
38038032Speter				**  the pipe.
38138032Speter				*/
38238032Speter
38338032Speter				/* close the write end of the pipe */
38438032Speter				(void) close(pipefd[1]);
38538032Speter
38638032Speter				/* we shouldn't be interrupted, but ... */
38738032Speter				while (read(pipefd[0], &c, 1) < 0 &&
38838032Speter				       errno == EINTR)
38938032Speter					continue;
39038032Speter				(void) close(pipefd[0]);
39138032Speter			}
39238032Speter
39338032Speter			/* determine host name */
39438032Speter			p = hostnamebyanyaddr(&RealHostAddr);
39538032Speter			if (strlen(p) > (SIZE_T) MAXNAME)
39638032Speter				p[MAXNAME] = '\0';
39738032Speter			RealHostName = newstr(p);
39838032Speter			setproctitle("startup with %s", p);
39938032Speter
40038032Speter			if ((inchannel = fdopen(t, "r")) == NULL ||
40138032Speter			    (t = dup(t)) < 0 ||
40238032Speter			    (outchannel = fdopen(t, "w")) == NULL)
40338032Speter			{
40438032Speter				syserr("cannot open SMTP server channel, fd=%d", t);
40538032Speter				exit(EX_OK);
40638032Speter			}
40738032Speter
40838032Speter			InChannel = inchannel;
40938032Speter			OutChannel = outchannel;
41038032Speter			DisConnected = FALSE;
41138032Speter
41238032Speter			/* open maps for check_relay ruleset */
41338032Speter			initmaps(FALSE, e);
41438032Speter
41538032Speter#ifdef XLA
41638032Speter			if (!xla_host_ok(RealHostName))
41738032Speter			{
41838032Speter				message("421 Too many SMTP sessions for this host");
41938032Speter				exit(EX_OK);
42038032Speter			}
42138032Speter#endif
42238032Speter
42338032Speter			break;
42438032Speter		}
42538032Speter
42638032Speter		/* parent -- keep track of children */
42738032Speter		proc_list_add(pid);
42838032Speter		(void) releasesignal(SIGCHLD);
42938032Speter
43038032Speter		/* close the read end of the synchronization pipe */
43138032Speter		if (pipefd[0] != -1)
43238032Speter			(void) close(pipefd[0]);
43338032Speter
43438032Speter		/* close the port so that others will hang (for a while) */
43538032Speter		(void) close(t);
43638032Speter
43738032Speter		/* release the child by closing the read end of the sync pipe */
43838032Speter		if (pipefd[1] != -1)
43938032Speter			(void) close(pipefd[1]);
44038032Speter	}
44138032Speter	if (tTd(15, 2))
44238032Speter		printf("getreq: returning\n");
44338032Speter	return;
44438032Speter}
44538032Speter/*
44638032Speter**  OPENDAEMONSOCKET -- open the SMTP socket
44738032Speter**
44838032Speter**	Deals with setting all appropriate options.  DaemonAddr must
44938032Speter**	be set up in advance.
45038032Speter**
45138032Speter**	Parameters:
45238032Speter**		firsttime -- set if this is the initial open.
45338032Speter**
45438032Speter**	Returns:
45538032Speter**		Size in bytes of the daemon socket addr.
45638032Speter**
45738032Speter**	Side Effects:
45838032Speter**		Leaves DaemonSocket set to the open socket.
45938032Speter**		Exits if the socket cannot be created.
46038032Speter*/
46138032Speter
46238032Speter#define MAXOPENTRIES	10	/* maximum number of tries to open connection */
46338032Speter
46438032Speterint
46538032Speteropendaemonsocket(firsttime)
46638032Speter	bool firsttime;
46738032Speter{
46838032Speter	int on = 1;
46938032Speter	int socksize = 0;
47038032Speter	int ntries = 0;
47138032Speter	int saveerrno;
47238032Speter
47338032Speter	if (tTd(15, 2))
47438032Speter		printf("opendaemonsocket()\n");
47538032Speter
47638032Speter	do
47738032Speter	{
47838032Speter		if (ntries > 0)
47938032Speter			sleep(5);
48038032Speter		if (firsttime || DaemonSocket < 0)
48138032Speter		{
48238032Speter			DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
48338032Speter			if (DaemonSocket < 0)
48438032Speter			{
48538032Speter				saveerrno = errno;
48638032Speter				syserr("opendaemonsocket: can't create server SMTP socket");
48738032Speter			  severe:
48838032Speter				if (LogLevel > 0)
48938032Speter					sm_syslog(LOG_ALERT, NOQID,
49038032Speter						"problem creating SMTP socket");
49138032Speter				DaemonSocket = -1;
49238032Speter				continue;
49338032Speter			}
49438032Speter
49538032Speter			/* turn on network debugging? */
49638032Speter			if (tTd(15, 101))
49738032Speter				(void) setsockopt(DaemonSocket, SOL_SOCKET,
49838032Speter						  SO_DEBUG, (char *)&on,
49938032Speter						  sizeof on);
50038032Speter
50138032Speter			(void) setsockopt(DaemonSocket, SOL_SOCKET,
50238032Speter					  SO_REUSEADDR, (char *)&on, sizeof on);
50338032Speter			(void) setsockopt(DaemonSocket, SOL_SOCKET,
50438032Speter					  SO_KEEPALIVE, (char *)&on, sizeof on);
50538032Speter
50638032Speter#ifdef SO_RCVBUF
50738032Speter			if (TcpRcvBufferSize > 0)
50838032Speter			{
50938032Speter				if (setsockopt(DaemonSocket, SOL_SOCKET,
51038032Speter					       SO_RCVBUF,
51138032Speter					       (char *) &TcpRcvBufferSize,
51238032Speter					       sizeof(TcpRcvBufferSize)) < 0)
51338032Speter					syserr("opendaemonsocket: setsockopt(SO_RCVBUF)");
51438032Speter			}
51538032Speter#endif
51638032Speter
51738032Speter			switch (DaemonAddr.sa.sa_family)
51838032Speter			{
51938032Speter# if NETINET
52038032Speter			  case AF_INET:
52138032Speter				socksize = sizeof DaemonAddr.sin;
52238032Speter				break;
52338032Speter# endif
52438032Speter
52538032Speter# if NETISO
52638032Speter			  case AF_ISO:
52738032Speter				socksize = sizeof DaemonAddr.siso;
52838032Speter				break;
52938032Speter# endif
53038032Speter
53138032Speter			  default:
53238032Speter				socksize = sizeof DaemonAddr;
53338032Speter				break;
53438032Speter			}
53538032Speter
53638032Speter			if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
53738032Speter			{
53838032Speter				/* probably another daemon already */
53938032Speter				saveerrno = errno;
54038032Speter				syserr("opendaemonsocket: cannot bind");
54138032Speter				(void) close(DaemonSocket);
54238032Speter				goto severe;
54338032Speter			}
54438032Speter		}
54538032Speter		if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
54638032Speter		{
54738032Speter			saveerrno = errno;
54838032Speter			syserr("opendaemonsocket: cannot listen");
54938032Speter			(void) close(DaemonSocket);
55038032Speter			goto severe;
55138032Speter		}
55238032Speter		return socksize;
55338032Speter	} while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
55438032Speter	syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
55538032Speter	finis();
55638032Speter	return -1;  /* avoid compiler warning on IRIX */
55738032Speter}
55838032Speter/*
55938032Speter**  CLRDAEMON -- reset the daemon connection
56038032Speter**
56138032Speter**	Parameters:
56238032Speter**		none.
56338032Speter**
56438032Speter**	Returns:
56538032Speter**		none.
56638032Speter**
56738032Speter**	Side Effects:
56838032Speter**		releases any resources used by the passive daemon.
56938032Speter*/
57038032Speter
57138032Spetervoid
57238032Speterclrdaemon()
57338032Speter{
57438032Speter	if (DaemonSocket >= 0)
57538032Speter		(void) close(DaemonSocket);
57638032Speter	DaemonSocket = -1;
57738032Speter}
57838032Speter/*
57938032Speter**  SETDAEMONOPTIONS -- set options for running the daemon
58038032Speter**
58138032Speter**	Parameters:
58238032Speter**		p -- the options line.
58338032Speter**
58438032Speter**	Returns:
58538032Speter**		none.
58638032Speter*/
58738032Speter
58838032Spetervoid
58938032Spetersetdaemonoptions(p)
59038032Speter	register char *p;
59138032Speter{
59238032Speter	if (DaemonAddr.sa.sa_family == AF_UNSPEC)
59338032Speter		DaemonAddr.sa.sa_family = AF_INET;
59438032Speter
59538032Speter	while (p != NULL)
59638032Speter	{
59738032Speter		register char *f;
59838032Speter		register char *v;
59938032Speter
60038032Speter		while (isascii(*p) && isspace(*p))
60138032Speter			p++;
60238032Speter		if (*p == '\0')
60338032Speter			break;
60438032Speter		f = p;
60538032Speter		p = strchr(p, ',');
60638032Speter		if (p != NULL)
60738032Speter			*p++ = '\0';
60838032Speter		v = strchr(f, '=');
60938032Speter		if (v == NULL)
61038032Speter			continue;
61138032Speter		while (isascii(*++v) && isspace(*v))
61238032Speter			continue;
61338032Speter		if (isascii(*f) && islower(*f))
61438032Speter			*f = toupper(*f);
61538032Speter
61638032Speter		switch (*f)
61738032Speter		{
61838032Speter		  case 'F':		/* address family */
61938032Speter			if (isascii(*v) && isdigit(*v))
62038032Speter				DaemonAddr.sa.sa_family = atoi(v);
62138032Speter#if NETINET
62238032Speter			else if (strcasecmp(v, "inet") == 0)
62338032Speter				DaemonAddr.sa.sa_family = AF_INET;
62438032Speter#endif
62538032Speter#if NETISO
62638032Speter			else if (strcasecmp(v, "iso") == 0)
62738032Speter				DaemonAddr.sa.sa_family = AF_ISO;
62838032Speter#endif
62938032Speter#if NETNS
63038032Speter			else if (strcasecmp(v, "ns") == 0)
63138032Speter				DaemonAddr.sa.sa_family = AF_NS;
63238032Speter#endif
63338032Speter#if NETX25
63438032Speter			else if (strcasecmp(v, "x.25") == 0)
63538032Speter				DaemonAddr.sa.sa_family = AF_CCITT;
63638032Speter#endif
63738032Speter			else
63838032Speter				syserr("554 Unknown address family %s in Family=option", v);
63938032Speter			break;
64038032Speter
64138032Speter		  case 'A':		/* address */
64238032Speter			switch (DaemonAddr.sa.sa_family)
64338032Speter			{
64438032Speter#if NETINET
64538032Speter			  case AF_INET:
64638032Speter				if (isascii(*v) && isdigit(*v))
64738032Speter					DaemonAddr.sin.sin_addr.s_addr = inet_addr(v);
64838032Speter				else
64938032Speter				{
65038032Speter					register struct hostent *hp;
65138032Speter
65238032Speter					hp = sm_gethostbyname(v);
65338032Speter					if (hp == NULL)
65438032Speter						syserr("554 host \"%s\" unknown", v);
65538032Speter					else
65638032Speter						bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ);
65738032Speter				}
65838032Speter				break;
65938032Speter#endif
66038032Speter
66138032Speter			  default:
66238032Speter				syserr("554 Address= option unsupported for family %d",
66338032Speter					DaemonAddr.sa.sa_family);
66438032Speter				break;
66538032Speter			}
66638032Speter			break;
66738032Speter
66838032Speter		  case 'P':		/* port */
66938032Speter			switch (DaemonAddr.sa.sa_family)
67038032Speter			{
67138032Speter#if NETISO
67238032Speter				short port;
67338032Speter#endif
67438032Speter
67538032Speter#if NETINET
67638032Speter			  case AF_INET:
67738032Speter				if (isascii(*v) && isdigit(*v))
67838032Speter					DaemonAddr.sin.sin_port = htons(atoi(v));
67938032Speter				else
68038032Speter				{
68138032Speter					register struct servent *sp;
68238032Speter
68338032Speter					sp = getservbyname(v, "tcp");
68438032Speter					if (sp == NULL)
68538032Speter						syserr("554 service \"%s\" unknown", v);
68638032Speter					else
68738032Speter						DaemonAddr.sin.sin_port = sp->s_port;
68838032Speter				}
68938032Speter				break;
69038032Speter#endif
69138032Speter
69238032Speter#if NETISO
69338032Speter			  case AF_ISO:
69438032Speter				/* assume two byte transport selector */
69538032Speter				if (isascii(*v) && isdigit(*v))
69638032Speter					port = htons(atoi(v));
69738032Speter				else
69838032Speter				{
69938032Speter					register struct servent *sp;
70038032Speter
70138032Speter					sp = getservbyname(v, "tcp");
70238032Speter					if (sp == NULL)
70338032Speter						syserr("554 service \"%s\" unknown", v);
70438032Speter					else
70538032Speter						port = sp->s_port;
70638032Speter				}
70738032Speter				bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
70838032Speter				break;
70938032Speter#endif
71038032Speter
71138032Speter			  default:
71238032Speter				syserr("554 Port= option unsupported for family %d",
71338032Speter					DaemonAddr.sa.sa_family);
71438032Speter				break;
71538032Speter			}
71638032Speter			break;
71738032Speter
71838032Speter		  case 'L':		/* listen queue size */
71938032Speter			ListenQueueSize = atoi(v);
72038032Speter			break;
72138032Speter
72238032Speter		  case 'S':		/* send buffer size */
72338032Speter			TcpSndBufferSize = atoi(v);
72438032Speter			break;
72538032Speter
72638032Speter		  case 'R':		/* receive buffer size */
72738032Speter			TcpRcvBufferSize = atoi(v);
72838032Speter			break;
72938032Speter
73038032Speter		  default:
73138032Speter			syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
73238032Speter		}
73338032Speter	}
73438032Speter}
73538032Speter/*
73638032Speter**  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
73738032Speter**
73838032Speter**	Parameters:
73938032Speter**		host -- the name of the host.
74038032Speter**		port -- the port number to connect to.
74138032Speter**		mci -- a pointer to the mail connection information
74238032Speter**			structure to be filled in.
74338032Speter**		e -- the current envelope.
74438032Speter**
74538032Speter**	Returns:
74638032Speter**		An exit code telling whether the connection could be
74738032Speter**			made and if not why not.
74838032Speter**
74938032Speter**	Side Effects:
75038032Speter**		none.
75138032Speter*/
75238032Speter
75338032Speterstatic jmp_buf	CtxConnectTimeout;
75438032Speter
75538032Speterstatic void
75638032Speterconnecttimeout()
75738032Speter{
75838032Speter	errno = ETIMEDOUT;
75938032Speter	longjmp(CtxConnectTimeout, 1);
76038032Speter}
76138032Speter
76238032SpeterSOCKADDR	CurHostAddr;		/* address of current host */
76338032Speter
76438032Speterint
76538032Spetermakeconnection(host, port, mci, e)
76638032Speter	char *host;
76738032Speter	u_short port;
76838032Speter	register MCI *mci;
76938032Speter	ENVELOPE *e;
77038032Speter{
77138032Speter	register volatile int addrno = 0;
77238032Speter	register volatile int s;
77338032Speter	register struct hostent *volatile hp = (struct hostent *)NULL;
77438032Speter	SOCKADDR addr;
77538032Speter	int sav_errno;
77638032Speter	volatile int addrlen;
77738032Speter	volatile bool firstconnect;
77838032Speter	EVENT *volatile ev = NULL;
77938032Speter
78038032Speter	/*
78138032Speter	**  Set up the address for the mailer.
78238032Speter	**	Accept "[a.b.c.d]" syntax for host name.
78338032Speter	*/
78438032Speter
78538032Speter#if NAMED_BIND
78638032Speter	h_errno = 0;
78738032Speter#endif
78838032Speter	errno = 0;
78938032Speter	bzero(&CurHostAddr, sizeof CurHostAddr);
79038032Speter	SmtpPhase = mci->mci_phase = "initial connection";
79138032Speter	CurHostName = host;
79238032Speter
79338032Speter	if (host[0] == '[')
79438032Speter	{
79538032Speter#if NETINET
79638032Speter		unsigned long hid = INADDR_NONE;
79738032Speter#endif
79838032Speter		register char *p = strchr(host, ']');
79938032Speter
80038032Speter		if (p != NULL)
80138032Speter		{
80238032Speter			*p = '\0';
80338032Speter#if NETINET
80438032Speter			hid = inet_addr(&host[1]);
80538032Speter			if (hid == INADDR_NONE)
80638032Speter#endif
80738032Speter			{
80838032Speter				/* try it as a host name (avoid MX lookup) */
80938032Speter				hp = sm_gethostbyname(&host[1]);
81038032Speter				if (hp == NULL && p[-1] == '.')
81138032Speter				{
81238032Speter#if NAMED_BIND
81338032Speter					int oldopts = _res.options;
81438032Speter
81538032Speter					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
81638032Speter#endif
81738032Speter					p[-1] = '\0';
81838032Speter					hp = sm_gethostbyname(&host[1]);
81938032Speter					p[-1] = '.';
82038032Speter#if NAMED_BIND
82138032Speter					_res.options = oldopts;
82238032Speter#endif
82338032Speter				}
82438032Speter				*p = ']';
82538032Speter				goto gothostent;
82638032Speter			}
82738032Speter			*p = ']';
82838032Speter		}
82938032Speter		if (p == NULL)
83038032Speter		{
83138032Speter			extern char MsgBuf[];
83238032Speter
83338032Speter			usrerr("553 Invalid numeric domain spec \"%s\"", host);
83438032Speter			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
83538032Speter			return EX_NOHOST;
83638032Speter		}
83738032Speter#if NETINET
83838032Speter		addr.sin.sin_family = AF_INET;		/*XXX*/
83938032Speter		addr.sin.sin_addr.s_addr = hid;
84038032Speter#endif
84138032Speter	}
84238032Speter	else
84338032Speter	{
84438032Speter		/* contortion to get around SGI cc complaints */
84538032Speter		{
84638032Speter			register char *p = &host[strlen(host) - 1];
84738032Speter
84838032Speter			hp = sm_gethostbyname(host);
84938032Speter			if (hp == NULL && *p == '.')
85038032Speter			{
85138032Speter#if NAMED_BIND
85238032Speter				int oldopts = _res.options;
85338032Speter
85438032Speter				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
85538032Speter#endif
85638032Speter				*p = '\0';
85738032Speter				hp = sm_gethostbyname(host);
85838032Speter				*p = '.';
85938032Speter#if NAMED_BIND
86038032Speter				_res.options = oldopts;
86138032Speter#endif
86238032Speter			}
86338032Speter		}
86438032Spetergothostent:
86538032Speter		if (hp == NULL)
86638032Speter		{
86738032Speter#if NAMED_BIND
86838032Speter			/* check for name server timeouts */
86938032Speter			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
87038032Speter			    (errno == ECONNREFUSED && UseNameServer))
87138032Speter			{
87238032Speter				mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
87338032Speter				return EX_TEMPFAIL;
87438032Speter			}
87538032Speter#endif
87638032Speter			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
87738032Speter			return (EX_NOHOST);
87838032Speter		}
87938032Speter		addr.sa.sa_family = hp->h_addrtype;
88038032Speter		switch (hp->h_addrtype)
88138032Speter		{
88238032Speter#if NETINET
88338032Speter		  case AF_INET:
88438032Speter			bcopy(hp->h_addr,
88538032Speter				&addr.sin.sin_addr,
88638032Speter				INADDRSZ);
88738032Speter			break;
88838032Speter#endif
88938032Speter
89038032Speter		  default:
89138032Speter			if (hp->h_length > sizeof addr.sa.sa_data)
89238032Speter			{
89338032Speter				syserr("makeconnection: long sa_data: family %d len %d",
89438032Speter					hp->h_addrtype, hp->h_length);
89538032Speter				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
89638032Speter				return EX_NOHOST;
89738032Speter			}
89838032Speter			bcopy(hp->h_addr,
89938032Speter				addr.sa.sa_data,
90038032Speter				hp->h_length);
90138032Speter			break;
90238032Speter		}
90338032Speter		addrno = 1;
90438032Speter	}
90538032Speter
90638032Speter	/*
90738032Speter	**  Determine the port number.
90838032Speter	*/
90938032Speter
91038032Speter	if (port == 0)
91138032Speter	{
91238032Speter		register struct servent *sp = getservbyname("smtp", "tcp");
91338032Speter
91438032Speter		if (sp == NULL)
91538032Speter		{
91638032Speter			if (LogLevel > 2)
91738032Speter				sm_syslog(LOG_ERR, NOQID,
91838032Speter					"makeconnection: service \"smtp\" unknown");
91938032Speter			port = htons(25);
92038032Speter		}
92138032Speter		else
92238032Speter			port = sp->s_port;
92338032Speter	}
92438032Speter
92538032Speter	switch (addr.sa.sa_family)
92638032Speter	{
92738032Speter#if NETINET
92838032Speter	  case AF_INET:
92938032Speter		addr.sin.sin_port = port;
93038032Speter		addrlen = sizeof (struct sockaddr_in);
93138032Speter		break;
93238032Speter#endif
93338032Speter
93438032Speter#if NETISO
93538032Speter	  case AF_ISO:
93638032Speter		/* assume two byte transport selector */
93738032Speter		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
93838032Speter		addrlen = sizeof (struct sockaddr_iso);
93938032Speter		break;
94038032Speter#endif
94138032Speter
94238032Speter	  default:
94338032Speter		syserr("Can't connect to address family %d", addr.sa.sa_family);
94438032Speter		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
94538032Speter		return (EX_NOHOST);
94638032Speter	}
94738032Speter
94838032Speter	/*
94938032Speter	**  Try to actually open the connection.
95038032Speter	*/
95138032Speter
95238032Speter#ifdef XLA
95338032Speter	/* if too many connections, don't bother trying */
95438032Speter	if (!xla_noqueue_ok(host))
95538032Speter		return EX_TEMPFAIL;
95638032Speter#endif
95738032Speter
95838032Speter	firstconnect = TRUE;
95938032Speter	for (;;)
96038032Speter	{
96138032Speter		if (tTd(16, 1))
96238032Speter			printf("makeconnection (%s [%s])\n",
96338032Speter				host, anynet_ntoa(&addr));
96438032Speter
96538032Speter		/* save for logging */
96638032Speter		CurHostAddr = addr;
96738032Speter
96838032Speter		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
96938032Speter		{
97038032Speter			int rport = IPPORT_RESERVED - 1;
97138032Speter
97238032Speter			s = rresvport(&rport);
97338032Speter		}
97438032Speter		else
97538032Speter		{
97638032Speter			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
97738032Speter		}
97838032Speter		if (s < 0)
97938032Speter		{
98038032Speter			sav_errno = errno;
98138032Speter			syserr("makeconnection: cannot create socket");
98238032Speter#ifdef XLA
98338032Speter			xla_host_end(host);
98438032Speter#endif
98538032Speter			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
98638032Speter			return EX_TEMPFAIL;
98738032Speter		}
98838032Speter
98938032Speter#ifdef SO_SNDBUF
99038032Speter		if (TcpSndBufferSize > 0)
99138032Speter		{
99238032Speter			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
99338032Speter				       (char *) &TcpSndBufferSize,
99438032Speter				       sizeof(TcpSndBufferSize)) < 0)
99538032Speter				syserr("makeconnection: setsockopt(SO_SNDBUF)");
99638032Speter		}
99738032Speter#endif
99838032Speter
99938032Speter		if (tTd(16, 1))
100038032Speter			printf("makeconnection: fd=%d\n", s);
100138032Speter
100238032Speter		/* turn on network debugging? */
100338032Speter		if (tTd(16, 101))
100438032Speter		{
100538032Speter			int on = 1;
100638032Speter			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
100738032Speter					  (char *)&on, sizeof on);
100838032Speter		}
100938032Speter		if (e->e_xfp != NULL)
101038032Speter			(void) fflush(e->e_xfp);		/* for debugging */
101138032Speter		errno = 0;					/* for debugging */
101238032Speter
101338032Speter		/*
101438032Speter		**  Linux seems to hang in connect for 90 minutes (!!!).
101538032Speter		**  Time out the connect to avoid this problem.
101638032Speter		*/
101738032Speter
101838032Speter		if (setjmp(CtxConnectTimeout) == 0)
101938032Speter		{
102038032Speter			int i;
102138032Speter
102238032Speter			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
102338032Speter				ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
102438032Speter			else if (TimeOuts.to_connect != 0)
102538032Speter				ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
102638032Speter			else
102738032Speter				ev = NULL;
102838032Speter
102938032Speter#if _FFR_CONNECTONLYTO_OPTION
103038032Speter			/* for testing */
103138032Speter			if (ConnectOnlyTo != 0)
103238032Speter				addr.sin.sin_addr.s_addr = ConnectOnlyTo;
103338032Speter#endif
103438032Speter			i = connect(s, (struct sockaddr *) &addr, addrlen);
103538032Speter			sav_errno = errno;
103638032Speter			if (ev != NULL)
103738032Speter				clrevent(ev);
103838032Speter			if (i >= 0)
103938032Speter				break;
104038032Speter		}
104138032Speter		else
104238032Speter			sav_errno = errno;
104338032Speter
104438032Speter		/* if running demand-dialed connection, try again */
104538032Speter		if (DialDelay > 0 && firstconnect)
104638032Speter		{
104738032Speter			if (tTd(16, 1))
104838032Speter				printf("Connect failed (%s); trying again...\n",
104938032Speter					errstring(sav_errno));
105038032Speter			firstconnect = FALSE;
105138032Speter			sleep(DialDelay);
105238032Speter			continue;
105338032Speter		}
105438032Speter
105538032Speter		/* couldn't connect.... figure out why */
105638032Speter		(void) close(s);
105738032Speter
105838032Speter		if (LogLevel >= 14)
105938032Speter			sm_syslog(LOG_INFO, e->e_id,
106038032Speter				  "makeconnection (%s [%s]) failed: %s",
106138032Speter				  host, anynet_ntoa(&addr),
106238032Speter				  errstring(sav_errno));
106338032Speter
106438032Speter		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
106538032Speter		{
106638032Speter			if (tTd(16, 1))
106738032Speter				printf("Connect failed (%s); trying new address....\n",
106838032Speter					errstring(sav_errno));
106938032Speter			switch (addr.sa.sa_family)
107038032Speter			{
107138032Speter#if NETINET
107238032Speter			  case AF_INET:
107338032Speter				bcopy(hp->h_addr_list[addrno++],
107438032Speter				      &addr.sin.sin_addr,
107538032Speter				      INADDRSZ);
107638032Speter				break;
107738032Speter#endif
107838032Speter
107938032Speter			  default:
108038032Speter				bcopy(hp->h_addr_list[addrno++],
108138032Speter					addr.sa.sa_data,
108238032Speter					hp->h_length);
108338032Speter				break;
108438032Speter			}
108538032Speter			continue;
108638032Speter		}
108738032Speter
108838032Speter		/* couldn't open connection */
108938032Speter#ifdef XLA
109038032Speter		xla_host_end(host);
109138032Speter#endif
109238032Speter		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
109338032Speter		return EX_TEMPFAIL;
109438032Speter	}
109538032Speter
109638032Speter	/* connection ok, put it into canonical form */
109738032Speter	if ((mci->mci_out = fdopen(s, "w")) == NULL ||
109838032Speter	    (s = dup(s)) < 0 ||
109938032Speter	    (mci->mci_in = fdopen(s, "r")) == NULL)
110038032Speter	{
110138032Speter		syserr("cannot open SMTP client channel, fd=%d", s);
110238032Speter		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
110338032Speter		return EX_TEMPFAIL;
110438032Speter	}
110538032Speter
110638032Speter	mci_setstat(mci, EX_OK, NULL, NULL);
110738032Speter	return (EX_OK);
110838032Speter}
110938032Speter/*
111038032Speter**  MYHOSTNAME -- return the name of this host.
111138032Speter**
111238032Speter**	Parameters:
111338032Speter**		hostbuf -- a place to return the name of this host.
111438032Speter**		size -- the size of hostbuf.
111538032Speter**
111638032Speter**	Returns:
111738032Speter**		A list of aliases for this host.
111838032Speter**
111938032Speter**	Side Effects:
112038032Speter**		Adds numeric codes to $=w.
112138032Speter*/
112238032Speter
112338032Speterstruct hostent *
112438032Spetermyhostname(hostbuf, size)
112538032Speter	char hostbuf[];
112638032Speter	int size;
112738032Speter{
112838032Speter	register struct hostent *hp;
112938032Speter
113038032Speter	if (gethostname(hostbuf, size) < 0)
113138032Speter	{
113238032Speter		(void) strcpy(hostbuf, "localhost");
113338032Speter	}
113438032Speter	hp = sm_gethostbyname(hostbuf);
113538032Speter	if (hp == NULL)
113638032Speter		return NULL;
113738032Speter	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
113838032Speter	{
113938032Speter		(void) strncpy(hostbuf, hp->h_name, size - 1);
114038032Speter		hostbuf[size - 1] = '\0';
114138032Speter	}
114238032Speter
114338032Speter	/*
114438032Speter	**  If there is still no dot in the name, try looking for a
114538032Speter	**  dotted alias.
114638032Speter	*/
114738032Speter
114838032Speter	if (strchr(hostbuf, '.') == NULL)
114938032Speter	{
115038032Speter		char **ha;
115138032Speter
115238032Speter		for (ha = hp->h_aliases; *ha != NULL; ha++)
115338032Speter		{
115438032Speter			if (strchr(*ha, '.') != NULL)
115538032Speter			{
115638032Speter				(void) strncpy(hostbuf, *ha, size - 1);
115738032Speter				hostbuf[size - 1] = '\0';
115838032Speter				break;
115938032Speter			}
116038032Speter		}
116138032Speter	}
116238032Speter
116338032Speter	/*
116438032Speter	**  If _still_ no dot, wait for a while and try again -- it is
116538032Speter	**  possible that some service is starting up.  This can result
116638032Speter	**  in excessive delays if the system is badly configured, but
116738032Speter	**  there really isn't a way around that, particularly given that
116838032Speter	**  the config file hasn't been read at this point.
116938032Speter	**  All in all, a bit of a mess.
117038032Speter	*/
117138032Speter
117238032Speter	if (strchr(hostbuf, '.') == NULL &&
117338032Speter	    !getcanonname(hostbuf, size, TRUE))
117438032Speter	{
117538032Speter		sm_syslog(LOG_CRIT, NOQID,
117638032Speter			"My unqualified host name (%s) unknown; sleeping for retry",
117738032Speter			hostbuf);
117838032Speter		message("My unqualified host name (%s) unknown; sleeping for retry",
117938032Speter			hostbuf);
118038032Speter		sleep(60);
118138032Speter		if (!getcanonname(hostbuf, size, TRUE))
118238032Speter		{
118338032Speter			sm_syslog(LOG_ALERT, NOQID,
118438032Speter				"unable to qualify my own domain name (%s) -- using short name",
118538032Speter				hostbuf);
118638032Speter			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
118738032Speter				hostbuf);
118838032Speter		}
118938032Speter	}
119038032Speter	return (hp);
119138032Speter}
119238032Speter/*
119338032Speter**  ADDRCMP -- compare two host addresses
119438032Speter**
119538032Speter**	Parameters:
119638032Speter**		hp -- hostent structure for the first address
119738032Speter**		ha -- actual first address
119838032Speter**		sa -- second address
119938032Speter**
120038032Speter**	Returns:
120138032Speter**		0 -- if ha and sa match
120238032Speter**		else -- they don't match
120338032Speter*/
120438032Speter
120538032Speterint
120638032Speteraddrcmp(hp, ha, sa)
120738032Speter	struct hostent *hp;
120838032Speter	char *ha;
120938032Speter	SOCKADDR *sa;
121038032Speter{
121138032Speter	switch (sa->sa.sa_family)
121238032Speter	{
121338032Speter	  case AF_INET:
121438032Speter		if (hp->h_addrtype == AF_INET)
121538032Speter			return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length);
121638032Speter		break;
121738032Speter
121838032Speter	}
121938032Speter	return -1;
122038032Speter}
122138032Speter/*
122238032Speter**  GETAUTHINFO -- get the real host name asociated with a file descriptor
122338032Speter**
122438032Speter**	Uses RFC1413 protocol to try to get info from the other end.
122538032Speter**
122638032Speter**	Parameters:
122738032Speter**		fd -- the descriptor
122838032Speter**		may_be_forged -- an outage that is set to TRUE if the
122938032Speter**			forward lookup of RealHostName does not match
123038032Speter**			RealHostAddr; set to FALSE if they do match.
123138032Speter**
123238032Speter**	Returns:
123338032Speter**		The user@host information associated with this descriptor.
123438032Speter*/
123538032Speter
123638032Speterstatic jmp_buf	CtxAuthTimeout;
123738032Speter
123838032Speterstatic void
123938032Speterauthtimeout()
124038032Speter{
124138032Speter	longjmp(CtxAuthTimeout, 1);
124238032Speter}
124338032Speter
124438032Speterchar *
124538032Spetergetauthinfo(fd, may_be_forged)
124638032Speter	int fd;
124738032Speter	bool *may_be_forged;
124838032Speter{
124938032Speter	SOCKADDR_LEN_T falen;
125038032Speter	register char *volatile p = NULL;
125138032Speter	SOCKADDR la;
125238032Speter	SOCKADDR_LEN_T lalen;
125338032Speter	register struct servent *sp;
125438032Speter	volatile int s;
125538032Speter	int i = 0;
125638032Speter	EVENT *ev;
125738032Speter	int nleft;
125838032Speter	struct hostent *hp;
125938032Speter	char *ostype = NULL;
126038032Speter	char **ha;
126138032Speter	char ibuf[MAXNAME + 1];
126238032Speter	static char hbuf[MAXNAME * 2 + 11];
126338032Speter
126438032Speter	*may_be_forged = FALSE;
126538032Speter	falen = sizeof RealHostAddr;
126638032Speter	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
126738032Speter	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
126838032Speter	{
126938032Speter		if (i < 0 && errno != ENOTSOCK)
127038032Speter			return NULL;
127138032Speter		(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
127238032Speter			RealUserName);
127338032Speter		if (tTd(9, 1))
127438032Speter			printf("getauthinfo: %s\n", hbuf);
127538032Speter		return hbuf;
127638032Speter	}
127738032Speter
127838032Speter	if (RealHostName == NULL)
127938032Speter	{
128038032Speter		/* translate that to a host name */
128138032Speter		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
128238032Speter		if (strlen(RealHostName) > MAXNAME)
128338032Speter			RealHostName[MAXNAME - 1] = '\0';
128438032Speter	}
128538032Speter
128638032Speter	/* cross check RealHostName with forward DNS lookup */
128738032Speter	if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
128838032Speter	    RealHostName[0] == '[')
128938032Speter	{
129038032Speter		/*
129138032Speter		** address is not a socket or have an
129238032Speter		** IP address with no forward lookup
129338032Speter		*/
129438032Speter		*may_be_forged = FALSE;
129538032Speter	}
129638032Speter	else
129738032Speter	{
129838032Speter		/* try to match the reverse against the forward lookup */
129938032Speter		hp = sm_gethostbyname(RealHostName);
130038032Speter
130138032Speter		if (hp == NULL)
130238032Speter			*may_be_forged = TRUE;
130338032Speter		else
130438032Speter		{
130538032Speter			for (ha = hp->h_addr_list; *ha != NULL; ha++)
130638032Speter				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
130738032Speter					break;
130838032Speter			*may_be_forged = *ha == NULL;
130938032Speter		}
131038032Speter	}
131138032Speter
131238032Speter	if (TimeOuts.to_ident == 0)
131338032Speter		goto noident;
131438032Speter
131538032Speter	lalen = sizeof la;
131638032Speter	if (RealHostAddr.sa.sa_family != AF_INET ||
131738032Speter	    getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
131838032Speter	    la.sa.sa_family != AF_INET)
131938032Speter	{
132038032Speter		/* no ident info */
132138032Speter		goto noident;
132238032Speter	}
132338032Speter
132438032Speter	/* create ident query */
132538032Speter	(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
132638032Speter		ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
132738032Speter
132838032Speter	/* create local address */
132938032Speter	la.sin.sin_port = 0;
133038032Speter
133138032Speter	/* create foreign address */
133238032Speter	sp = getservbyname("auth", "tcp");
133338032Speter	if (sp != NULL)
133438032Speter		RealHostAddr.sin.sin_port = sp->s_port;
133538032Speter	else
133638032Speter		RealHostAddr.sin.sin_port = htons(113);
133738032Speter
133838032Speter	s = -1;
133938032Speter	if (setjmp(CtxAuthTimeout) != 0)
134038032Speter	{
134138032Speter		if (s >= 0)
134238032Speter			(void) close(s);
134338032Speter		goto noident;
134438032Speter	}
134538032Speter
134638032Speter	/* put a timeout around the whole thing */
134738032Speter	ev = setevent(TimeOuts.to_ident, authtimeout, 0);
134838032Speter
134938032Speter	/* connect to foreign IDENT server using same address as SMTP socket */
135038032Speter	s = socket(AF_INET, SOCK_STREAM, 0);
135138032Speter	if (s < 0)
135238032Speter	{
135338032Speter		clrevent(ev);
135438032Speter		goto noident;
135538032Speter	}
135638032Speter	if (bind(s, &la.sa, sizeof la.sin) < 0 ||
135738032Speter	    connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
135838032Speter	{
135938032Speter		goto closeident;
136038032Speter	}
136138032Speter
136238032Speter	if (tTd(9, 10))
136338032Speter		printf("getauthinfo: sent %s", ibuf);
136438032Speter
136538032Speter	/* send query */
136638032Speter	if (write(s, ibuf, strlen(ibuf)) < 0)
136738032Speter		goto closeident;
136838032Speter
136938032Speter	/* get result */
137038032Speter	p = &ibuf[0];
137138032Speter	nleft = sizeof ibuf - 1;
137238032Speter	while ((i = read(s, p, nleft)) > 0)
137338032Speter	{
137438032Speter		p += i;
137538032Speter		nleft -= i;
137638032Speter		*p = '\0';
137738032Speter		if (strchr(ibuf, '\n') != NULL)
137838032Speter			break;
137938032Speter	}
138038032Speter	(void) close(s);
138138032Speter	clrevent(ev);
138238032Speter	if (i < 0 || p == &ibuf[0])
138338032Speter		goto noident;
138438032Speter
138538032Speter	if (*--p == '\n' && *--p == '\r')
138638032Speter		p--;
138738032Speter	*++p = '\0';
138838032Speter
138938032Speter	if (tTd(9, 3))
139038032Speter		printf("getauthinfo:  got %s\n", ibuf);
139138032Speter
139238032Speter	/* parse result */
139338032Speter	p = strchr(ibuf, ':');
139438032Speter	if (p == NULL)
139538032Speter	{
139638032Speter		/* malformed response */
139738032Speter		goto noident;
139838032Speter	}
139938032Speter	while (isascii(*++p) && isspace(*p))
140038032Speter		continue;
140138032Speter	if (strncasecmp(p, "userid", 6) != 0)
140238032Speter	{
140338032Speter		/* presumably an error string */
140438032Speter		goto noident;
140538032Speter	}
140638032Speter	p += 6;
140738032Speter	while (isascii(*p) && isspace(*p))
140838032Speter		p++;
140938032Speter	if (*p++ != ':')
141038032Speter	{
141138032Speter		/* either useridxx or malformed response */
141238032Speter		goto noident;
141338032Speter	}
141438032Speter
141538032Speter	/* p now points to the OSTYPE field */
141638032Speter	while (isascii(*p) && isspace(*p))
141738032Speter		p++;
141838032Speter	ostype = p;
141938032Speter	p = strchr(p, ':');
142038032Speter	if (p == NULL)
142138032Speter	{
142238032Speter		/* malformed response */
142338032Speter		goto noident;
142438032Speter	}
142538032Speter	else
142638032Speter	{
142738032Speter		char *charset;
142838032Speter
142938032Speter		*p = '\0';
143038032Speter		charset = strchr(ostype, ',');
143138032Speter		if (charset != NULL)
143238032Speter			*charset = '\0';
143338032Speter	}
143438032Speter
143538032Speter	/* 1413 says don't do this -- but it's broken otherwise */
143638032Speter	while (isascii(*++p) && isspace(*p))
143738032Speter		continue;
143838032Speter
143938032Speter	/* p now points to the authenticated name -- copy carefully */
144038032Speter	if (strncasecmp(ostype, "other", 5) == 0 &&
144138032Speter	    (ostype[5] == ' ' || ostype[5] == '\0'))
144238032Speter	{
144338032Speter		snprintf(hbuf, sizeof hbuf, "IDENT:");
144438032Speter		cleanstrcpy(&hbuf[6], p, MAXNAME);
144538032Speter	}
144638032Speter	else
144738032Speter		cleanstrcpy(hbuf, p, MAXNAME);
144838032Speter	i = strlen(hbuf);
144938032Speter	snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
145038032Speter		 RealHostName == NULL ? "localhost" : RealHostName);
145138032Speter	goto postident;
145238032Speter
145338032Spetercloseident:
145438032Speter	(void) close(s);
145538032Speter	clrevent(ev);
145638032Speter
145738032Speternoident:
145838032Speter	if (RealHostName == NULL)
145938032Speter	{
146038032Speter		if (tTd(9, 1))
146138032Speter			printf("getauthinfo: NULL\n");
146238032Speter		return NULL;
146338032Speter	}
146438032Speter	snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
146538032Speter
146638032Speterpostident:
146738032Speter#if IP_SRCROUTE
146838032Speter# ifndef GET_IPOPT_DST
146938032Speter#  define GET_IPOPT_DST(dst)	(dst)
147038032Speter# endif
147138032Speter	/*
147238032Speter	**  Extract IP source routing information.
147338032Speter	**
147438032Speter	**	Format of output for a connection from site a through b
147538032Speter	**	through c to d:
147638032Speter	**		loose:      @site-c@site-b:site-a
147738032Speter	**		strict:	   !@site-c@site-b:site-a
147838032Speter	**
147938032Speter	**	o - pointer within ipopt_list structure.
148038032Speter	**	q - pointer within ls/ss rr route data
148138032Speter	**	p - pointer to hbuf
148238032Speter	*/
148338032Speter
148438032Speter	if (RealHostAddr.sa.sa_family == AF_INET)
148538032Speter	{
148638032Speter		SOCKOPT_LEN_T ipoptlen;
148738032Speter		int j;
148838032Speter		u_char *q;
148938032Speter		u_char *o;
149038032Speter		int l;
149138032Speter		struct in_addr addr;
149238032Speter		struct ipoption ipopt;
149338032Speter
149438032Speter		ipoptlen = sizeof ipopt;
149538032Speter		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
149638032Speter			       (char *) &ipopt, &ipoptlen) < 0)
149738032Speter			goto noipsr;
149838032Speter		if (ipoptlen == 0)
149938032Speter			goto noipsr;
150038032Speter		o = (u_char *) ipopt.ipopt_list;
150138032Speter		while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
150238032Speter		{
150338032Speter			switch (*o)
150438032Speter			{
150538032Speter			  case IPOPT_EOL:
150638032Speter				o = NULL;
150738032Speter				break;
150838032Speter
150938032Speter			  case IPOPT_NOP:
151038032Speter				o++;
151138032Speter				break;
151238032Speter
151338032Speter			  case IPOPT_SSRR:
151438032Speter			  case IPOPT_LSRR:
151538032Speter				/*
151638032Speter				**  Source routing.
151738032Speter				**	o[0] is the option type (loose/strict).
151838032Speter				**	o[1] is the length of this option,
151938032Speter				**		including option type and
152038032Speter				**		length.
152138032Speter				**	o[2] is the pointer into the route
152238032Speter				**		data.
152338032Speter				**	o[3] begins the route data.
152438032Speter				*/
152538032Speter
152638032Speter				p = &hbuf[strlen(hbuf)];
152738032Speter				l = sizeof hbuf - (hbuf - p) - 6;
152838032Speter				snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
152938032Speter				    *o == IPOPT_SSRR ? "!" : "",
153038032Speter				    l > 240 ? 120 : l / 2,
153138032Speter				    inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst)));
153238032Speter				i = strlen(p);
153338032Speter				p += i;
153438032Speter				l -= strlen(p);
153538032Speter
153638032Speter				j = o[1] / sizeof(struct in_addr) - 1;
153738032Speter
153838032Speter				/* q skips length and router pointer to data */
153938032Speter				q = &o[3];
154038032Speter				for ( ; j >= 0; j--)
154138032Speter				{
154238032Speter					memcpy(&addr, q, sizeof(addr));
154338032Speter					snprintf(p, SPACELEFT(hbuf, p),
154438032Speter						"%c%.*s",
154538032Speter						j != 0 ? '@' : ':',
154638032Speter						l > 240 ? 120 :
154738032Speter						    j == 0 ? l : l / 2,
154838032Speter						inet_ntoa(addr));
154938032Speter					i = strlen(p);
155038032Speter					p += i;
155138032Speter					l -= i + 1;
155238032Speter					q += sizeof(struct in_addr);
155338032Speter				}
155438032Speter				o += o[1];
155538032Speter				break;
155638032Speter
155738032Speter			  default:
155838032Speter				/* Skip over option */
155938032Speter				o += o[1];
156038032Speter				break;
156138032Speter			}
156238032Speter		}
156338032Speter		snprintf(p, SPACELEFT(hbuf, p), "]");
156438032Speter		goto postipsr;
156538032Speter	}
156638032Speter
156738032Speternoipsr:
156838032Speter#endif
156938032Speter	if (RealHostName != NULL && RealHostName[0] != '[')
157038032Speter	{
157138032Speter		p = &hbuf[strlen(hbuf)];
157238032Speter		(void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
157338032Speter			anynet_ntoa(&RealHostAddr));
157438032Speter	}
157538032Speter	if (*may_be_forged)
157638032Speter	{
157738032Speter		p = &hbuf[strlen(hbuf)];
157838032Speter		(void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
157938032Speter	}
158038032Speter
158138032Speter#if IP_SRCROUTE
158238032Speterpostipsr:
158338032Speter#endif
158438032Speter	if (tTd(9, 1))
158538032Speter		printf("getauthinfo: %s\n", hbuf);
158638032Speter	return hbuf;
158738032Speter}
158838032Speter/*
158938032Speter**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
159038032Speter**
159138032Speter**	Parameters:
159238032Speter**		map -- a pointer to this map.
159338032Speter**		name -- the (presumably unqualified) hostname.
159438032Speter**		av -- unused -- for compatibility with other mapping
159538032Speter**			functions.
159638032Speter**		statp -- an exit status (out parameter) -- set to
159738032Speter**			EX_TEMPFAIL if the name server is unavailable.
159838032Speter**
159938032Speter**	Returns:
160038032Speter**		The mapping, if found.
160138032Speter**		NULL if no mapping found.
160238032Speter**
160338032Speter**	Side Effects:
160438032Speter**		Looks up the host specified in hbuf.  If it is not
160538032Speter**		the canonical name for that host, return the canonical
160638032Speter**		name (unless MF_MATCHONLY is set, which will cause the
160738032Speter**		status only to be returned).
160838032Speter*/
160938032Speter
161038032Speterchar *
161138032Speterhost_map_lookup(map, name, av, statp)
161238032Speter	MAP *map;
161338032Speter	char *name;
161438032Speter	char **av;
161538032Speter	int *statp;
161638032Speter{
161738032Speter	register struct hostent *hp;
161838032Speter	struct in_addr in_addr;
161938032Speter	char *cp;
162038032Speter	register STAB *s;
162138032Speter	char hbuf[MAXNAME + 1];
162238032Speter
162338032Speter	/*
162438032Speter	**  See if we have already looked up this name.  If so, just
162538032Speter	**  return it.
162638032Speter	*/
162738032Speter
162838032Speter	s = stab(name, ST_NAMECANON, ST_ENTER);
162938032Speter	if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
163038032Speter	{
163138032Speter		if (tTd(9, 1))
163238032Speter			printf("host_map_lookup(%s) => CACHE %s\n",
163338032Speter			       name,
163438032Speter			       s->s_namecanon.nc_cname == NULL
163538032Speter					? "NULL"
163638032Speter					: s->s_namecanon.nc_cname);
163738032Speter		errno = s->s_namecanon.nc_errno;
163838032Speter#if NAMED_BIND
163938032Speter		h_errno = s->s_namecanon.nc_herrno;
164038032Speter#endif
164138032Speter		*statp = s->s_namecanon.nc_stat;
164238032Speter		if (*statp == EX_TEMPFAIL)
164338032Speter		{
164438032Speter			CurEnv->e_status = "4.4.3";
164538032Speter			message("851 %s: Name server timeout",
164638032Speter				shortenstring(name, 33));
164738032Speter		}
164838032Speter		if (*statp != EX_OK)
164938032Speter			return NULL;
165038032Speter		if (s->s_namecanon.nc_cname == NULL)
165138032Speter		{
165238032Speter			syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
165338032Speter				name,
165438032Speter				s->s_namecanon.nc_errno,
165538032Speter				s->s_namecanon.nc_herrno);
165638032Speter			return NULL;
165738032Speter		}
165838032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
165938032Speter			cp = map_rewrite(map, name, strlen(name), NULL);
166038032Speter		else
166138032Speter			cp = map_rewrite(map,
166238032Speter					 s->s_namecanon.nc_cname,
166338032Speter					 strlen(s->s_namecanon.nc_cname),
166438032Speter					 av);
166538032Speter		return cp;
166638032Speter	}
166738032Speter
166838032Speter	/*
166938032Speter	**  If we are running without a regular network connection (usually
167038032Speter	**  dial-on-demand) and we are just queueing, we want to avoid DNS
167138032Speter	**  lookups because those could try to connect to a server.
167238032Speter	*/
167338032Speter
167438032Speter	if (CurEnv->e_sendmode == SM_DEFER)
167538032Speter	{
167638032Speter		if (tTd(9, 1))
167738032Speter			printf("host_map_lookup(%s) => DEFERRED\n", name);
167838032Speter		*statp = EX_TEMPFAIL;
167938032Speter		return NULL;
168038032Speter	}
168138032Speter
168238032Speter	/*
168338032Speter	**  If first character is a bracket, then it is an address
168438032Speter	**  lookup.  Address is copied into a temporary buffer to
168538032Speter	**  strip the brackets and to preserve name if address is
168638032Speter	**  unknown.
168738032Speter	*/
168838032Speter
168938032Speter	if (*name != '[')
169038032Speter	{
169138032Speter		if (tTd(9, 1))
169238032Speter			printf("host_map_lookup(%s) => ", name);
169338032Speter		s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
169438032Speter		snprintf(hbuf, sizeof hbuf, "%s", name);
169538032Speter		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
169638032Speter		{
169738032Speter			if (tTd(9, 1))
169838032Speter				printf("%s\n", hbuf);
169938032Speter			s->s_namecanon.nc_stat = EX_OK;
170038032Speter			s->s_namecanon.nc_cname = newstr(hbuf);
170138032Speter			if (bitset(MF_MATCHONLY, map->map_mflags))
170238032Speter				cp = map_rewrite(map, name, strlen(name), NULL);
170338032Speter			else
170438032Speter				cp = map_rewrite(map, hbuf, strlen(hbuf), av);
170538032Speter			return cp;
170638032Speter		}
170738032Speter		else
170838032Speter		{
170938032Speter			s->s_namecanon.nc_errno = errno;
171038032Speter#if NAMED_BIND
171138032Speter			s->s_namecanon.nc_herrno = h_errno;
171238032Speter			if (tTd(9, 1))
171338032Speter				printf("FAIL (%d)\n", h_errno);
171438032Speter			switch (h_errno)
171538032Speter			{
171638032Speter			  case TRY_AGAIN:
171738032Speter				if (UseNameServer)
171838032Speter				{
171938032Speter					CurEnv->e_status = "4.4.3";
172038032Speter					message("851 %s: Name server timeout",
172138032Speter						shortenstring(name, 33));
172238032Speter				}
172338032Speter				*statp = EX_TEMPFAIL;
172438032Speter				break;
172538032Speter
172638032Speter			  case HOST_NOT_FOUND:
172738032Speter			  case NO_DATA:
172838032Speter				*statp = EX_NOHOST;
172938032Speter				break;
173038032Speter
173138032Speter			  case NO_RECOVERY:
173238032Speter				*statp = EX_SOFTWARE;
173338032Speter				break;
173438032Speter
173538032Speter			  default:
173638032Speter				*statp = EX_UNAVAILABLE;
173738032Speter				break;
173838032Speter			}
173938032Speter#else
174038032Speter			if (tTd(9, 1))
174138032Speter				printf("FAIL\n");
174238032Speter			*statp = EX_NOHOST;
174338032Speter#endif
174438032Speter			s->s_namecanon.nc_stat = *statp;
174538032Speter			return NULL;
174638032Speter		}
174738032Speter	}
174838032Speter	if ((cp = strchr(name, ']')) == NULL)
174938032Speter		return (NULL);
175038032Speter	*cp = '\0';
175138032Speter	in_addr.s_addr = inet_addr(&name[1]);
175238032Speter	*cp = ']';
175338032Speter
175438032Speter	/* nope -- ask the name server */
175538032Speter	hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET);
175638032Speter	s->s_namecanon.nc_errno = errno;
175738032Speter#if NAMED_BIND
175838032Speter	s->s_namecanon.nc_herrno = h_errno;
175938032Speter#endif
176038032Speter	s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
176138032Speter	if (hp == NULL)
176238032Speter	{
176338032Speter		s->s_namecanon.nc_stat = *statp = EX_NOHOST;
176438032Speter		return (NULL);
176538032Speter	}
176638032Speter
176738032Speter	/* found a match -- copy out */
176838032Speter	hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE);
176938032Speter	s->s_namecanon.nc_stat = *statp = EX_OK;
177038032Speter	s->s_namecanon.nc_cname = newstr(hp->h_name);
177138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
177238032Speter		cp = map_rewrite(map, name, strlen(name), NULL);
177338032Speter	else
177438032Speter		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
177538032Speter	return cp;
177638032Speter}
177738032Speter
177838032Speter# else /* DAEMON */
177938032Speter/* code for systems without sophisticated networking */
178038032Speter
178138032Speter/*
178238032Speter**  MYHOSTNAME -- stub version for case of no daemon code.
178338032Speter**
178438032Speter**	Can't convert to upper case here because might be a UUCP name.
178538032Speter**
178638032Speter**	Mark, you can change this to be anything you want......
178738032Speter*/
178838032Speter
178938032Speterchar **
179038032Spetermyhostname(hostbuf, size)
179138032Speter	char hostbuf[];
179238032Speter	int size;
179338032Speter{
179438032Speter	register FILE *f;
179538032Speter
179638032Speter	hostbuf[0] = '\0';
179738032Speter	f = fopen("/usr/include/whoami", "r");
179838032Speter	if (f != NULL)
179938032Speter	{
180038032Speter		(void) fgets(hostbuf, size, f);
180138032Speter		fixcrlf(hostbuf, TRUE);
180238032Speter		(void) fclose(f);
180338032Speter	}
180438032Speter	return (NULL);
180538032Speter}
180638032Speter/*
180738032Speter**  GETAUTHINFO -- get the real host name asociated with a file descriptor
180838032Speter**
180938032Speter**	Parameters:
181038032Speter**		fd -- the descriptor
181138032Speter**		may_be_forged -- an outage that is set to TRUE if the
181238032Speter**			forward lookup of RealHostName does not match
181338032Speter**			RealHostAddr; set to FALSE if they do match.
181438032Speter**
181538032Speter**	Returns:
181638032Speter**		The host name associated with this descriptor, if it can
181738032Speter**			be determined.
181838032Speter**		NULL otherwise.
181938032Speter**
182038032Speter**	Side Effects:
182138032Speter**		none
182238032Speter*/
182338032Speter
182438032Speterchar *
182538032Spetergetauthinfo(fd, may_be_forged)
182638032Speter	int fd;
182738032Speter	bool *may_be_forged;
182838032Speter{
182938032Speter	*may_be_forged = FALSE;
183038032Speter	return NULL;
183138032Speter}
183238032Speter/*
183338032Speter**  MAPHOSTNAME -- turn a hostname into canonical form
183438032Speter**
183538032Speter**	Parameters:
183638032Speter**		map -- a pointer to the database map.
183738032Speter**		name -- a buffer containing a hostname.
183838032Speter**		avp -- a pointer to a (cf file defined) argument vector.
183938032Speter**		statp -- an exit status (out parameter).
184038032Speter**
184138032Speter**	Returns:
184238032Speter**		mapped host name
184338032Speter**		FALSE otherwise.
184438032Speter**
184538032Speter**	Side Effects:
184638032Speter**		Looks up the host specified in name.  If it is not
184738032Speter**		the canonical name for that host, replace it with
184838032Speter**		the canonical name.  If the name is unknown, or it
184938032Speter**		is already the canonical name, leave it unchanged.
185038032Speter*/
185138032Speter
185238032Speter/*ARGSUSED*/
185338032Speterchar *
185438032Speterhost_map_lookup(map, name, avp, statp)
185538032Speter	MAP *map;
185638032Speter	char *name;
185738032Speter	char **avp;
185838032Speter	char *statp;
185938032Speter{
186038032Speter	register struct hostent *hp;
186138032Speter	char *cp;
186238032Speter
186338032Speter	hp = sm_gethostbyname(name);
186438032Speter	if (hp == NULL)
186538032Speter	{
186638032Speter		*statp = EX_NOHOST;
186738032Speter		return NULL;
186838032Speter	}
186938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
187038032Speter		cp = map_rewrite(map, name, strlen(name), NULL);
187138032Speter	else
187238032Speter		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
187338032Speter	return cp;
187438032Speter}
187538032Speter
187638032Speter#endif /* DAEMON */
187738032Speter/*
187838032Speter**  HOST_MAP_INIT -- initialize host class structures
187938032Speter*/
188038032Speter
188138032Speterbool
188238032Speterhost_map_init(map, args)
188338032Speter	MAP *map;
188438032Speter	char *args;
188538032Speter{
188638032Speter	register char *p = args;
188738032Speter
188838032Speter	for (;;)
188938032Speter	{
189038032Speter		while (isascii(*p) && isspace(*p))
189138032Speter			p++;
189238032Speter		if (*p != '-')
189338032Speter			break;
189438032Speter		switch (*++p)
189538032Speter		{
189638032Speter		  case 'a':
189738032Speter			map->map_app = ++p;
189838032Speter			break;
189938032Speter
190038032Speter		  case 'T':
190138032Speter			map->map_tapp = ++p;
190238032Speter			break;
190338032Speter
190438032Speter		  case 'm':
190538032Speter			map->map_mflags |= MF_MATCHONLY;
190638032Speter			break;
190738032Speter
190838032Speter		  case 't':
190938032Speter			map->map_mflags |= MF_NODEFER;
191038032Speter			break;
191138032Speter		}
191238032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
191338032Speter			p++;
191438032Speter		if (*p != '\0')
191538032Speter			*p++ = '\0';
191638032Speter	}
191738032Speter	if (map->map_app != NULL)
191838032Speter		map->map_app = newstr(map->map_app);
191938032Speter	if (map->map_tapp != NULL)
192038032Speter		map->map_tapp = newstr(map->map_tapp);
192138032Speter	return TRUE;
192238032Speter}
192338032Speter/*
192438032Speter**  ANYNET_NTOA -- convert a network address to printable form.
192538032Speter**
192638032Speter**	Parameters:
192738032Speter**		sap -- a pointer to a sockaddr structure.
192838032Speter**
192938032Speter**	Returns:
193038032Speter**		A printable version of that sockaddr.
193138032Speter*/
193238032Speter
193338032Speter#ifdef USE_SOCK_STREAM
193438032Speter
193538032Speter#if NETLINK
193638032Speter# include <net/if_dl.h>
193738032Speter#endif
193838032Speter
193938032Speterchar *
194038032Speteranynet_ntoa(sap)
194138032Speter	register SOCKADDR *sap;
194238032Speter{
194338032Speter	register char *bp;
194438032Speter	register char *ap;
194538032Speter	int l;
194638032Speter	static char buf[100];
194738032Speter
194838032Speter	/* check for null/zero family */
194938032Speter	if (sap == NULL)
195038032Speter		return "NULLADDR";
195138032Speter	if (sap->sa.sa_family == 0)
195238032Speter		return "0";
195338032Speter
195438032Speter	switch (sap->sa.sa_family)
195538032Speter	{
195638032Speter#if NETUNIX
195738032Speter	  case AF_UNIX:
195838032Speter	  	if (sap->sunix.sun_path[0] != '\0')
195938032Speter	  		snprintf(buf, sizeof buf, "[UNIX: %.64s]",
196038032Speter				sap->sunix.sun_path);
196138032Speter	  	else
196238032Speter	  		snprintf(buf, sizeof buf, "[UNIX: localhost]");
196338032Speter		return buf;
196438032Speter#endif
196538032Speter
196638032Speter#if NETINET
196738032Speter	  case AF_INET:
196838032Speter		return inet_ntoa(sap->sin.sin_addr);
196938032Speter#endif
197038032Speter
197138032Speter#if NETLINK
197238032Speter	  case AF_LINK:
197338032Speter		snprintf(buf, sizeof buf, "[LINK: %s]",
197438032Speter			link_ntoa((struct sockaddr_dl *) &sap->sa));
197538032Speter		return buf;
197638032Speter#endif
197738032Speter	  default:
197838032Speter		/* this case is needed when nothing is #defined */
197938032Speter		/* in order to keep the switch syntactically correct */
198038032Speter		break;
198138032Speter	}
198238032Speter
198338032Speter	/* unknown family -- just dump bytes */
198438032Speter	(void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
198538032Speter	bp = &buf[strlen(buf)];
198638032Speter	ap = sap->sa.sa_data;
198738032Speter	for (l = sizeof sap->sa.sa_data; --l >= 0; )
198838032Speter	{
198938032Speter		(void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
199038032Speter		bp += 3;
199138032Speter	}
199238032Speter	*--bp = '\0';
199338032Speter	return buf;
199438032Speter}
199538032Speter/*
199638032Speter**  HOSTNAMEBYANYADDR -- return name of host based on address
199738032Speter**
199838032Speter**	Parameters:
199938032Speter**		sap -- SOCKADDR pointer
200038032Speter**
200138032Speter**	Returns:
200238032Speter**		text representation of host name.
200338032Speter**
200438032Speter**	Side Effects:
200538032Speter**		none.
200638032Speter*/
200738032Speter
200838032Speterchar *
200938032Speterhostnamebyanyaddr(sap)
201038032Speter	register SOCKADDR *sap;
201138032Speter{
201238032Speter	register struct hostent *hp;
201338032Speter	int saveretry;
201438032Speter
201538032Speter#if NAMED_BIND
201638032Speter	/* shorten name server timeout to avoid higher level timeouts */
201738032Speter	saveretry = _res.retry;
201838032Speter	_res.retry = 3;
201938032Speter#endif /* NAMED_BIND */
202038032Speter
202138032Speter	switch (sap->sa.sa_family)
202238032Speter	{
202338032Speter#if NETINET
202438032Speter	  case AF_INET:
202538032Speter		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
202638032Speter			INADDRSZ,
202738032Speter			AF_INET);
202838032Speter		break;
202938032Speter#endif
203038032Speter
203138032Speter#if NETISO
203238032Speter	  case AF_ISO:
203338032Speter		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
203438032Speter			sizeof sap->siso.siso_addr,
203538032Speter			AF_ISO);
203638032Speter		break;
203738032Speter#endif
203838032Speter
203938032Speter#if NETUNIX
204038032Speter	  case AF_UNIX:
204138032Speter		hp = NULL;
204238032Speter		break;
204338032Speter#endif
204438032Speter
204538032Speter	  default:
204638032Speter		hp = sm_gethostbyaddr(sap->sa.sa_data,
204738032Speter			   sizeof sap->sa.sa_data,
204838032Speter			   sap->sa.sa_family);
204938032Speter		break;
205038032Speter	}
205138032Speter
205238032Speter#if NAMED_BIND
205338032Speter	_res.retry = saveretry;
205438032Speter#endif /* NAMED_BIND */
205538032Speter
205638032Speter	if (hp != NULL && hp->h_name[0] != '[' &&
205738032Speter	    inet_addr(hp->h_name) == INADDR_NONE)
205838032Speter		return denlstring((char *) hp->h_name, TRUE, TRUE);
205938032Speter#if NETUNIX
206038032Speter	else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
206138032Speter		return "localhost";
206238032Speter#endif
206338032Speter	else
206438032Speter	{
206538032Speter		/* produce a dotted quad */
206638032Speter		static char buf[203];
206738032Speter
206838032Speter		(void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
206938032Speter		return buf;
207038032Speter	}
207138032Speter}
207238032Speter
207338032Speter#endif /* SOCK_STREAM */
2074