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