xref: /original-bsd/usr.sbin/sendmail/src/daemon.c (revision bfb80540)
1939f5b94Sdist /*
20942ea6aSbostic  * Copyright (c) 1983 Eric P. Allman
3da1c6175Sbostic  * Copyright (c) 1988 Regents of the University of California.
4da1c6175Sbostic  * All rights reserved.
5da1c6175Sbostic  *
63bc94712Sbostic  * %sccs.include.redist.c%
7939f5b94Sdist  */
8939f5b94Sdist 
97aa493c5Seric #include <errno.h>
10a8c080f0Seric #include <signal.h>
116c05f684Sbostic #include "sendmail.h"
127fa39d90Seric 
13af5e902cSeric #ifndef lint
14da1c6175Sbostic #ifdef DAEMON
15*bfb80540Seric static char sccsid[] = "@(#)daemon.c	6.26 (Berkeley) 03/29/93 (with daemon mode)";
16d0a9e852Seric #else
17*bfb80540Seric static char sccsid[] = "@(#)daemon.c	6.26 (Berkeley) 03/29/93 (without daemon mode)";
18da1c6175Sbostic #endif
19da1c6175Sbostic #endif /* not lint */
20da1c6175Sbostic 
21da1c6175Sbostic #ifdef DAEMON
22d0a9e852Seric 
231c71e510Seric # include <netdb.h>
241e1663f7Swnj # include <sys/wait.h>
25af5e902cSeric # include <sys/time.h>
26d0a9e852Seric 
27e2f2f828Seric #ifdef NETISO
28e2f2f828Seric # include <netiso/iso.h>
29e2f2f828Seric #endif
30e2f2f828Seric 
317fa39d90Seric /*
327fa39d90Seric **  DAEMON.C -- routines to use when running as a daemon.
3347b12ae1Seric **
3447b12ae1Seric **	This entire file is highly dependent on the 4.2 BSD
3547b12ae1Seric **	interprocess communication primitives.  No attempt has
3647b12ae1Seric **	been made to make this file portable to Version 7,
3747b12ae1Seric **	Version 6, MPX files, etc.  If you should try such a
3847b12ae1Seric **	thing yourself, I recommend chucking the entire file
3947b12ae1Seric **	and starting from scratch.  Basic semantics are:
4047b12ae1Seric **
4147b12ae1Seric **	getrequests()
4247b12ae1Seric **		Opens a port and initiates a connection.
4347b12ae1Seric **		Returns in a child.  Must set InChannel and
4447b12ae1Seric **		OutChannel appropriately.
45b7d7afcbSeric **	clrdaemon()
46b7d7afcbSeric **		Close any open files associated with getting
47b7d7afcbSeric **		the connection; this is used when running the queue,
48b7d7afcbSeric **		etc., to avoid having extra file descriptors during
49b7d7afcbSeric **		the queue run and to avoid confusing the network
50b7d7afcbSeric **		code (if it cares).
51914346b1Seric **	makeconnection(host, port, outfile, infile, usesecureport)
5247b12ae1Seric **		Make a connection to the named host on the given
5347b12ae1Seric **		port.  Set *outfile and *infile to the files
5447b12ae1Seric **		appropriate for communication.  Returns zero on
5547b12ae1Seric **		success, else an exit status describing the
5647b12ae1Seric **		error.
5705b57da8Seric **	maphostname(map, hbuf, hbufsiz, avp)
5805b57da8Seric **		Convert the entry in hbuf into a canonical form.
597fa39d90Seric */
60e2f2f828Seric 
61e2f2f828Seric extern char	*anynet_ntoa();
627fa39d90Seric /*
637fa39d90Seric **  GETREQUESTS -- open mail IPC port and get requests.
647fa39d90Seric **
657fa39d90Seric **	Parameters:
667fa39d90Seric **		none.
677fa39d90Seric **
687fa39d90Seric **	Returns:
697fa39d90Seric **		none.
707fa39d90Seric **
717fa39d90Seric **	Side Effects:
727fa39d90Seric **		Waits until some interesting activity occurs.  When
737fa39d90Seric **		it does, a child is created to process it, and the
747fa39d90Seric **		parent waits for completion.  Return from this
75147303b1Seric **		routine is always in the child.  The file pointers
76147303b1Seric **		"InChannel" and "OutChannel" should be set to point
77147303b1Seric **		to the communication channel.
787fa39d90Seric */
797fa39d90Seric 
80b7d7afcbSeric int		DaemonSocket	= -1;		/* fd describing socket */
81*bfb80540Seric SOCKADDR	DaemonAddr;			/* socket for incoming */
821c71e510Seric 
837fa39d90Seric getrequests()
847fa39d90Seric {
851c71e510Seric 	int t;
861c71e510Seric 	register struct servent *sp;
877868dfc2Seric 	int on = 1;
8815d084d5Seric 	bool refusingconnections = TRUE;
890aae1086Seric 	FILE *pidf;
909b100374Sbostic 	extern void reapchild();
91eb889047Seric 
92a8268164Seric 	/*
931c71e510Seric 	**  Set up the address for the mailer.
94eb889047Seric 	*/
95eb889047Seric 
96*bfb80540Seric 	if (DaemonAddr.sin.sin_family == 0)
97*bfb80540Seric 		DaemonAddr.sin.sin_family = AF_INET;
98*bfb80540Seric 	if (DaemonAddr.sin.sin_addr.s_addr == 0)
99*bfb80540Seric 		DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
100*bfb80540Seric 	if (DaemonAddr.sin.sin_port == 0)
101*bfb80540Seric 	{
1021c71e510Seric 		sp = getservbyname("smtp", "tcp");
1031c71e510Seric 		if (sp == NULL)
104d0a9e852Seric 		{
10508b25121Seric 			syserr("554 server \"smtp\" unknown");
106a1961f2aSeric 			goto severe;
1071c71e510Seric 		}
108*bfb80540Seric 		DaemonAddr.sin.sin_port = sp->s_port;
109*bfb80540Seric 	}
1101c71e510Seric 
1111c71e510Seric 	/*
1121c71e510Seric 	**  Try to actually open the connection.
1131c71e510Seric 	*/
1141c71e510Seric 
1151c71e510Seric 	if (tTd(15, 1))
116*bfb80540Seric 		printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
1171c71e510Seric 
1181c71e510Seric 	/* get a socket for the SMTP connection */
119af5e902cSeric 	DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
120b7d7afcbSeric 	if (DaemonSocket < 0)
1211c71e510Seric 	{
1221c71e510Seric 		/* probably another daemon already */
1231c71e510Seric 		syserr("getrequests: can't create socket");
1241c71e510Seric 	  severe:
125b0ba8827Seric # ifdef LOG
126b0ba8827Seric 		if (LogLevel > 0)
1270c034190Seric 			syslog(LOG_ALERT, "problem creating SMTP socket");
1286c2c3107Seric # endif /* LOG */
12947b12ae1Seric 		finis();
130d0a9e852Seric 	}
1311b6e4a15Seric 
1321b6e4a15Seric 	/* turn on network debugging? */
133a2ef5fa4Seric 	if (tTd(15, 101))
13452308a50Seric 		(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
1351b6e4a15Seric 
1367868dfc2Seric 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
1377868dfc2Seric 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
1387868dfc2Seric 
139*bfb80540Seric 	if (bind(DaemonSocket, &DaemonAddr.sa, sizeof DaemonAddr) < 0)
1401c71e510Seric 	{
1411c71e510Seric 		syserr("getrequests: cannot bind");
142b7d7afcbSeric 		(void) close(DaemonSocket);
1431c71e510Seric 		goto severe;
1441c71e510Seric 	}
1451c71e510Seric 
1461cd247eeSeric 	(void) signal(SIGCHLD, reapchild);
14752308a50Seric 
1480aae1086Seric 	/* write the pid to the log file for posterity */
1490aae1086Seric 	pidf = fopen(PidFile, "w");
1500aae1086Seric 	if (pidf != NULL)
1510aae1086Seric 	{
1520aae1086Seric 		fprintf(pidf, "%d\n", getpid());
1530aae1086Seric 		fclose(pidf);
1540aae1086Seric 	}
1550aae1086Seric 
1560aae1086Seric 
1571c71e510Seric 	if (tTd(15, 1))
158b7d7afcbSeric 		printf("getrequests: %d\n", DaemonSocket);
1591c71e510Seric 
1601c71e510Seric 	for (;;)
1611c71e510Seric 	{
1623a099713Seric 		register int pid;
163a44d5a5eSeric 		auto int lotherend;
16415d084d5Seric 		extern bool refuseconnections();
1653a099713Seric 
1663a099713Seric 		/* see if we are rejecting connections */
16715d084d5Seric 		CurrentLA = getla();
16815d084d5Seric 		if (refuseconnections())
1696775ec03Sbostic 		{
17015d084d5Seric 			if (!refusingconnections)
17115d084d5Seric 			{
17215d084d5Seric 				/* don't queue so peer will fail quickly */
17315d084d5Seric 				(void) listen(DaemonSocket, 0);
17415d084d5Seric 				refusingconnections = TRUE;
17515d084d5Seric 			}
17671e5e267Seric 			setproctitle("rejecting connections: load average: %d",
17771e5e267Seric 				CurrentLA);
1783a099713Seric 			sleep(5);
17915d084d5Seric 			continue;
18015d084d5Seric 		}
18115d084d5Seric 
18215d084d5Seric 		if (refusingconnections)
18315d084d5Seric 		{
18415d084d5Seric 			/* start listening again */
18515d084d5Seric 			if (listen(DaemonSocket, 10) < 0)
18615d084d5Seric 			{
18715d084d5Seric 				syserr("getrequests: cannot listen");
18815d084d5Seric 				(void) close(DaemonSocket);
18915d084d5Seric 				goto severe;
19015d084d5Seric 			}
19115d084d5Seric 			setproctitle("accepting connections");
19215d084d5Seric 			refusingconnections = FALSE;
1936775ec03Sbostic 		}
194a44d5a5eSeric 
1951c71e510Seric 		/* wait for a connection */
1961c71e510Seric 		do
1971c71e510Seric 		{
1981c71e510Seric 			errno = 0;
1999f9a15b6Skarels 			lotherend = sizeof RealHostAddr;
2009b100374Sbostic 			t = accept(DaemonSocket,
2019b100374Sbostic 			    (struct sockaddr *)&RealHostAddr, &lotherend);
2021c71e510Seric 		} while (t < 0 && errno == EINTR);
2031c71e510Seric 		if (t < 0)
2041c71e510Seric 		{
2051c71e510Seric 			syserr("getrequests: accept");
2061c71e510Seric 			sleep(5);
2071c71e510Seric 			continue;
2081c71e510Seric 		}
209d0a9e852Seric 
210d0a9e852Seric 		/*
211d0a9e852Seric 		**  Create a subprocess to process the mail.
212d0a9e852Seric 		*/
213d0a9e852Seric 
21461e4310fSeric 		if (tTd(15, 2))
2151c71e510Seric 			printf("getrequests: forking (fd = %d)\n", t);
216eb889047Seric 
217a8268164Seric 		pid = fork();
218a8268164Seric 		if (pid < 0)
219a8268164Seric 		{
220a8268164Seric 			syserr("daemon: cannot fork");
221a8268164Seric 			sleep(10);
2221c71e510Seric 			(void) close(t);
223a8268164Seric 			continue;
224a8268164Seric 		}
225a8268164Seric 
226a8268164Seric 		if (pid == 0)
227a8268164Seric 		{
228a44d5a5eSeric 			extern struct hostent *gethostbyaddr();
229a44d5a5eSeric 			register struct hostent *hp;
230a44d5a5eSeric 			char buf[MAXNAME];
231a44d5a5eSeric 
232a8268164Seric 			/*
233a8268164Seric 			**  CHILD -- return to caller.
234a44d5a5eSeric 			**	Collect verified idea of sending host.
235a8268164Seric 			**	Verify calling user id if possible here.
236a8268164Seric 			*/
237a8268164Seric 
2381cd247eeSeric 			(void) signal(SIGCHLD, SIG_DFL);
239779ac194Seric 
240a44d5a5eSeric 			/* determine host name */
24183c1f4bcSeric 			switch (RealHostAddr.sa.sa_family)
24283c1f4bcSeric 			{
24383c1f4bcSeric #ifdef NETINET
24483c1f4bcSeric 			  case AF_INET:
24583c1f4bcSeric 				hp = gethostbyaddr((char *) &RealHostAddr.sin.sin_addr,
24683c1f4bcSeric 					sizeof RealHostAddr.sin.sin_addr,
24783c1f4bcSeric 					AF_INET);
24883c1f4bcSeric 				break;
24983c1f4bcSeric #endif
25083c1f4bcSeric 
25183c1f4bcSeric #ifdef NETISO
25283c1f4bcSeric 			  case AF_ISO:
25383c1f4bcSeric 				hp = gethostbyaddr((char *) &RealHostAddr.siso.siso_addr,
25483c1f4bcSeric 					sizeof RealHostAddr.siso.siso_addr,
25583c1f4bcSeric 					AF_ISO);
25683c1f4bcSeric 				break;
25783c1f4bcSeric #endif
25883c1f4bcSeric 
25983c1f4bcSeric 			  default:
26083c1f4bcSeric 				hp = gethostbyaddr(RealHostAddr.sa.sa_data,
26183c1f4bcSeric 					   sizeof RealHostAddr.sa.sa_data,
26283c1f4bcSeric 					   RealHostAddr.sa.sa_family);
26383c1f4bcSeric 				break;
26483c1f4bcSeric 			}
26583c1f4bcSeric 
266a44d5a5eSeric 			if (hp != NULL)
267fefbbe29Seric 				(void) strcpy(buf, hp->h_name);
268a44d5a5eSeric 			else
26929dcf4baSeric 			{
27029dcf4baSeric 				/* produce a dotted quad */
27129dcf4baSeric 				(void) sprintf(buf, "[%s]",
272e2f2f828Seric 					anynet_ntoa(&RealHostAddr));
27329dcf4baSeric 			}
27429dcf4baSeric 
2752a6bc25bSeric #ifdef LOG
276845e533cSeric 			if (LogLevel > 10)
2772a6bc25bSeric 			{
2782a6bc25bSeric 				/* log connection information */
2792a6bc25bSeric 				syslog(LOG_INFO, "connect from %s (%s)",
280e2f2f828Seric 					buf, anynet_ntoa(&RealHostAddr));
2812a6bc25bSeric 			}
2822a6bc25bSeric #endif
2832a6bc25bSeric 
28429dcf4baSeric 			/* should we check for illegal connection here? XXX */
28529dcf4baSeric 
286a44d5a5eSeric 			RealHostName = newstr(buf);
287a44d5a5eSeric 
288b7d7afcbSeric 			(void) close(DaemonSocket);
2891c71e510Seric 			InChannel = fdopen(t, "r");
2901d5bd586Seric 			OutChannel = fdopen(dup(t), "w");
29161e4310fSeric 			if (tTd(15, 2))
292d0a9e852Seric 				printf("getreq: returning\n");
293a8268164Seric 			return;
294a8268164Seric 		}
295a8268164Seric 
2963c154354Seric 		/* close the port so that others will hang (for a while) */
2973c154354Seric 		(void) close(t);
2988e3e4b17Seric 	}
2993c154354Seric 	/*NOTREACHED*/
3003c154354Seric }
3018e3e4b17Seric /*
302b7d7afcbSeric **  CLRDAEMON -- reset the daemon connection
303b7d7afcbSeric **
304b7d7afcbSeric **	Parameters:
305b7d7afcbSeric **		none.
306b7d7afcbSeric **
307b7d7afcbSeric **	Returns:
308b7d7afcbSeric **		none.
309b7d7afcbSeric **
310b7d7afcbSeric **	Side Effects:
311b7d7afcbSeric **		releases any resources used by the passive daemon.
312b7d7afcbSeric */
313b7d7afcbSeric 
314b7d7afcbSeric clrdaemon()
315b7d7afcbSeric {
316b7d7afcbSeric 	if (DaemonSocket >= 0)
317b7d7afcbSeric 		(void) close(DaemonSocket);
318b7d7afcbSeric 	DaemonSocket = -1;
319b7d7afcbSeric }
320b7d7afcbSeric /*
321*bfb80540Seric **  SETDAEMONOPTIONS -- set options for running the daemon
322*bfb80540Seric **
323*bfb80540Seric **	Parameters:
324*bfb80540Seric **		p -- the options line.
325*bfb80540Seric **
326*bfb80540Seric **	Returns:
327*bfb80540Seric **		none.
328*bfb80540Seric */
329*bfb80540Seric 
330*bfb80540Seric setdaemonoptions(p)
331*bfb80540Seric 	register char *p;
332*bfb80540Seric {
333*bfb80540Seric 	while (p != NULL)
334*bfb80540Seric 	{
335*bfb80540Seric 		register char *f;
336*bfb80540Seric 		register char *v;
337*bfb80540Seric 
338*bfb80540Seric 		while (isascii(*p) && isspace(*p))
339*bfb80540Seric 			p++;
340*bfb80540Seric 		if (*p == '\0')
341*bfb80540Seric 			break;
342*bfb80540Seric 		f = p;
343*bfb80540Seric 		p = strchr(p, ',');
344*bfb80540Seric 		if (p != NULL)
345*bfb80540Seric 			*p++ = '\0';
346*bfb80540Seric 		v = strchr(f, '=');
347*bfb80540Seric 		if (v == NULL)
348*bfb80540Seric 			continue;
349*bfb80540Seric 		while (isascii(*++v) && isspace(*v))
350*bfb80540Seric 			continue;
351*bfb80540Seric 
352*bfb80540Seric 		switch (*f)
353*bfb80540Seric 		{
354*bfb80540Seric 		  case 'P':		/* port */
355*bfb80540Seric 		  case 'p':
356*bfb80540Seric 			if (isascii(*v) && isdigit(*v))
357*bfb80540Seric 				DaemonAddr.sin.sin_port = atoi(v);
358*bfb80540Seric 			else
359*bfb80540Seric 			{
360*bfb80540Seric 				register struct servent *sp;
361*bfb80540Seric 
362*bfb80540Seric 				sp = getservbyname(v, "tcp");
363*bfb80540Seric 				if (sp == NULL)
364*bfb80540Seric 					syserr("554 server \"%s\" unknown", v);
365*bfb80540Seric 				else
366*bfb80540Seric 					DaemonAddr.sin.sin_port = sp->s_port;
367*bfb80540Seric 			}
368*bfb80540Seric 			break;
369*bfb80540Seric 
370*bfb80540Seric 		  case 'A':		/* address */
371*bfb80540Seric 		  case 'a':
372*bfb80540Seric 			if (isascii(*v) && isdigit(*v))
373*bfb80540Seric 				(void) inet_aton(v, &DaemonAddr.sin.sin_addr);
374*bfb80540Seric 			else
375*bfb80540Seric 			{
376*bfb80540Seric 				register struct netent *np;
377*bfb80540Seric 
378*bfb80540Seric 				np = getnetbyname(v);
379*bfb80540Seric 				if (np == NULL)
380*bfb80540Seric 					syserr("554 network \"%s\" unknown", v);
381*bfb80540Seric 				else
382*bfb80540Seric 					DaemonAddr.sin.sin_addr.s_addr = np->n_net;
383*bfb80540Seric 			}
384*bfb80540Seric 			break;
385*bfb80540Seric 		}
386*bfb80540Seric 	}
387*bfb80540Seric }
388*bfb80540Seric /*
3897aa493c5Seric **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
3907aa493c5Seric **
3917aa493c5Seric **	Parameters:
3927aa493c5Seric **		host -- the name of the host.
39348ff0a9dSeric **		port -- the port number to connect to.
394655feedbSeric **		mci -- a pointer to the mail connection information
395655feedbSeric **			structure to be filled in.
396914346b1Seric **		usesecureport -- if set, use a low numbered (reserved)
397914346b1Seric **			port to provide some rudimentary authentication.
3987aa493c5Seric **
3997aa493c5Seric **	Returns:
4007aa493c5Seric **		An exit code telling whether the connection could be
4017aa493c5Seric **			made and if not why not.
4027aa493c5Seric **
4037aa493c5Seric **	Side Effects:
4047aa493c5Seric **		none.
4057aa493c5Seric */
4067aa493c5Seric 
407e2f2f828Seric SOCKADDR	CurHostAddr;		/* address of current host */
40871ff6caaSeric 
409b31e7f2bSeric int
410655feedbSeric makeconnection(host, port, mci, usesecureport)
4117aa493c5Seric 	char *host;
412210215eaSeric 	u_short port;
413b31e7f2bSeric 	register MCI *mci;
414914346b1Seric 	bool usesecureport;
4157aa493c5Seric {
41604344589Sbloom 	register int i, s;
41704344589Sbloom 	register struct hostent *hp = (struct hostent *)NULL;
418e2f2f828Seric 	SOCKADDR addr;
4196286bb75Sbloom 	int sav_errno;
420e2f2f828Seric 	int addrlen;
421134746fbSeric #ifdef NAMED_BIND
422134746fbSeric 	extern int h_errno;
423134746fbSeric #endif
4247aa493c5Seric 
4257aa493c5Seric 	/*
4267aa493c5Seric 	**  Set up the address for the mailer.
42771096d12Seric 	**	Accept "[a.b.c.d]" syntax for host name.
4287aa493c5Seric 	*/
4297aa493c5Seric 
430134746fbSeric #ifdef NAMED_BIND
431794bdbb9Smiriam 	h_errno = 0;
432134746fbSeric #endif
433794bdbb9Smiriam 	errno = 0;
434794bdbb9Smiriam 
43571096d12Seric 	if (host[0] == '[')
43671096d12Seric 	{
437a44d5a5eSeric 		long hid;
4386c2c3107Seric 		register char *p = strchr(host, ']');
43971096d12Seric 
440a44d5a5eSeric 		if (p != NULL)
44171096d12Seric 		{
442a44d5a5eSeric 			*p = '\0';
443a44d5a5eSeric 			hid = inet_addr(&host[1]);
444a7e21fe6Seric 			if (hid == -1)
445a7e21fe6Seric 			{
446a7e21fe6Seric 				/* try it as a host name (avoid MX lookup) */
447a7e21fe6Seric 				hp = gethostbyname(&host[1]);
448a7e21fe6Seric 				*p = ']';
449a7e21fe6Seric 				goto gothostent;
450a7e21fe6Seric 			}
451a44d5a5eSeric 			*p = ']';
45271096d12Seric 		}
453a7e21fe6Seric 		if (p == NULL)
45471096d12Seric 		{
45508b25121Seric 			usrerr("553 Invalid numeric domain spec \"%s\"", host);
45671096d12Seric 			return (EX_NOHOST);
45771096d12Seric 		}
45883c1f4bcSeric 		addr.sin.sin_family = AF_INET;
45983c1f4bcSeric 		addr.sin.sin_addr.s_addr = hid;
46071096d12Seric 	}
4611c71e510Seric 	else
4621c71e510Seric 	{
46304344589Sbloom 		hp = gethostbyname(host);
464a7e21fe6Seric gothostent:
465794bdbb9Smiriam 		if (hp == NULL)
466794bdbb9Smiriam 		{
467134746fbSeric #ifdef NAMED_BIND
468794bdbb9Smiriam 			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
46952308a50Seric 				return (EX_TEMPFAIL);
47082e5d8ddSeric 
471134746fbSeric 			/* if name server is specified, assume temp fail */
472134746fbSeric 			if (errno == ECONNREFUSED && UseNameServer)
473134746fbSeric 				return (EX_TEMPFAIL);
474134746fbSeric #endif
4757aa493c5Seric 			return (EX_NOHOST);
476794bdbb9Smiriam 		}
47783c1f4bcSeric 		addr.sa.sa_family = hp->h_addrtype;
47883c1f4bcSeric 		switch (hp->h_addrtype)
47983c1f4bcSeric 		{
48083c1f4bcSeric #ifdef NETINET
48183c1f4bcSeric 		  case AF_INET:
482e2f2f828Seric 			bcopy(hp->h_addr,
48383c1f4bcSeric 				&addr.sin.sin_addr,
484e2f2f828Seric 				hp->h_length);
48583c1f4bcSeric 			break;
48683c1f4bcSeric #endif
48783c1f4bcSeric 
48883c1f4bcSeric 		  default:
489e2f2f828Seric 			bcopy(hp->h_addr,
49083c1f4bcSeric 				addr.sa.sa_data,
491e2f2f828Seric 				hp->h_length);
49283c1f4bcSeric 			break;
49383c1f4bcSeric 		}
49404344589Sbloom 		i = 1;
4951c71e510Seric 	}
4961c71e510Seric 
4971c71e510Seric 	/*
4981c71e510Seric 	**  Determine the port number.
4991c71e510Seric 	*/
5001c71e510Seric 
501fd7c0790Seric 	if (port != 0)
502e2f2f828Seric 		port = htons(port);
503fd7c0790Seric 	else
5041c71e510Seric 	{
5051c71e510Seric 		register struct servent *sp = getservbyname("smtp", "tcp");
5061c71e510Seric 
5071c71e510Seric 		if (sp == NULL)
5081c71e510Seric 		{
50908b25121Seric 			syserr("554 makeconnection: server \"smtp\" unknown");
510845e533cSeric 			return (EX_OSERR);
5111c71e510Seric 		}
512e2f2f828Seric 		port = sp->s_port;
513e2f2f828Seric 	}
514e2f2f828Seric 
51583c1f4bcSeric 	switch (addr.sa.sa_family)
516e2f2f828Seric 	{
517e2f2f828Seric 	  case AF_INET:
51883c1f4bcSeric 		addr.sin.sin_port = port;
519e2f2f828Seric 		addrlen = sizeof (struct sockaddr_in);
520e2f2f828Seric 		break;
521e2f2f828Seric 
522e2f2f828Seric #ifdef NETISO
523e2f2f828Seric 	  case AF_ISO:
524e2f2f828Seric 		/* assume two byte transport selector */
525e2f2f828Seric 		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
526e2f2f828Seric 		addrlen = sizeof (struct sockaddr_iso);
527e2f2f828Seric 		break;
528e2f2f828Seric #endif
529e2f2f828Seric 
530e2f2f828Seric 	  default:
53183c1f4bcSeric 		syserr("Can't connect to address family %d", addr.sa.sa_family);
532e2f2f828Seric 		return (EX_NOHOST);
5331c71e510Seric 	}
5347aa493c5Seric 
5357aa493c5Seric 	/*
5367aa493c5Seric 	**  Try to actually open the connection.
5377aa493c5Seric 	*/
5387aa493c5Seric 
539aea02ca1Seric 	for (;;)
540aea02ca1Seric 	{
54161e4310fSeric 		if (tTd(16, 1))
542e2f2f828Seric 			printf("makeconnection (%s [%s])\n",
543e2f2f828Seric 				host, anynet_ntoa(&addr));
5447aa493c5Seric 
545226e3022Seric 		/* save for logging */
546226e3022Seric 		CurHostAddr = addr;
547226e3022Seric 
548914346b1Seric 		if (usesecureport)
549914346b1Seric 		{
550914346b1Seric 			int rport = IPPORT_RESERVED - 1;
551914346b1Seric 
552914346b1Seric 			s = rresvport(&rport);
553914346b1Seric 		}
554914346b1Seric 		else
555914346b1Seric 		{
556af5e902cSeric 			s = socket(AF_INET, SOCK_STREAM, 0);
557914346b1Seric 		}
5587aa493c5Seric 		if (s < 0)
5597aa493c5Seric 		{
5606286bb75Sbloom 			sav_errno = errno;
561914346b1Seric 			syserr("makeconnection: no socket");
5627aa493c5Seric 			goto failure;
5637aa493c5Seric 		}
5647aa493c5Seric 
56561e4310fSeric 		if (tTd(16, 1))
566b31e7f2bSeric 			printf("makeconnection: fd=%d\n", s);
5671b6e4a15Seric 
5681b6e4a15Seric 		/* turn on network debugging? */
569a2ef5fa4Seric 		if (tTd(16, 101))
57052308a50Seric 		{
57152308a50Seric 			int on = 1;
572aea02ca1Seric 			(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
573aea02ca1Seric 					  (char *)&on, sizeof on);
57452308a50Seric 		}
57587d6e633Srick 		if (CurEnv->e_xfp != NULL)
576877a6142Seric 			(void) fflush(CurEnv->e_xfp);		/* for debugging */
5774bd6a662Seric 		errno = 0;					/* for debugging */
578e2f2f828Seric 		if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
579aea02ca1Seric 			break;
580aea02ca1Seric 
581aea02ca1Seric 		/* couldn't connect.... figure out why */
5826286bb75Sbloom 		sav_errno = errno;
5836286bb75Sbloom 		(void) close(s);
58404344589Sbloom 		if (hp && hp->h_addr_list[i])
58504344589Sbloom 		{
586e2f2f828Seric 			extern char *errstring();
587e2f2f828Seric 
588aea02ca1Seric 			if (tTd(16, 1))
589e2f2f828Seric 				printf("Connect failed (%s); trying new address....\n",
590e2f2f828Seric 					errstring(sav_errno));
59183c1f4bcSeric 			switch (addr.sa.sa_family)
59283c1f4bcSeric 			{
59383c1f4bcSeric #ifdef NETINET
59483c1f4bcSeric 			  case AF_INET:
595e2f2f828Seric 				bcopy(hp->h_addr_list[i++],
59683c1f4bcSeric 				      &addr.sin.sin_addr,
597e2f2f828Seric 				      hp->h_length);
59883c1f4bcSeric 				break;
59983c1f4bcSeric #endif
60083c1f4bcSeric 
60183c1f4bcSeric 			  default:
602e2f2f828Seric 				bcopy(hp->h_addr_list[i++],
60383c1f4bcSeric 					addr.sa.sa_data,
604914346b1Seric 					hp->h_length);
60583c1f4bcSeric 				break;
60683c1f4bcSeric 			}
607aea02ca1Seric 			continue;
60804344589Sbloom 		}
60904344589Sbloom 
6107aa493c5Seric 		/* failure, decide if temporary or not */
6117aa493c5Seric 	failure:
612e2de2524Seric 		if (transienterror(sav_errno))
613e2de2524Seric 			return EX_TEMPFAIL;
614e2de2524Seric 		else
61587d6e633Srick 		{
61687d6e633Srick 			extern char *errstring();
61787d6e633Srick 
61808b25121Seric 			message("%s", errstring(sav_errno));
6197aa493c5Seric 			return (EX_UNAVAILABLE);
6207aa493c5Seric 		}
6217aa493c5Seric 	}
6227aa493c5Seric 
6237aa493c5Seric 	/* connection ok, put it into canonical form */
624655feedbSeric 	mci->mci_out = fdopen(s, "w");
625655feedbSeric 	mci->mci_in = fdopen(dup(s), "r");
6267aa493c5Seric 
627dca8e1f7Seric 	return (EX_OK);
6287aa493c5Seric }
629444eaf03Seric /*
630444eaf03Seric **  MYHOSTNAME -- return the name of this host.
631444eaf03Seric **
632444eaf03Seric **	Parameters:
633444eaf03Seric **		hostbuf -- a place to return the name of this host.
634897f1869Seric **		size -- the size of hostbuf.
635444eaf03Seric **
636444eaf03Seric **	Returns:
637444eaf03Seric **		A list of aliases for this host.
638444eaf03Seric **
639444eaf03Seric **	Side Effects:
64038ad259dSeric **		Sets the MyIpAddrs buffer to a list of my IP addresses.
641444eaf03Seric */
642444eaf03Seric 
64338ad259dSeric struct in_addr	MyIpAddrs[MAXIPADDR + 1];
64438ad259dSeric 
645444eaf03Seric char **
646897f1869Seric myhostname(hostbuf, size)
647444eaf03Seric 	char hostbuf[];
648897f1869Seric 	int size;
649444eaf03Seric {
65038ad259dSeric 	register struct hostent *hp;
651444eaf03Seric 	extern struct hostent *gethostbyname();
652444eaf03Seric 
653af5e902cSeric 	if (gethostname(hostbuf, size) < 0)
654af5e902cSeric 	{
655af5e902cSeric 		(void) strcpy(hostbuf, "localhost");
656af5e902cSeric 	}
657a44d5a5eSeric 	hp = gethostbyname(hostbuf);
658a44d5a5eSeric 	if (hp != NULL)
6597364df9fSeric 	{
66038ad259dSeric 		(void) strncpy(hostbuf, hp->h_name, size - 1);
66138ad259dSeric 		hostbuf[size - 1] = '\0';
66238ad259dSeric 
66338ad259dSeric 		if (hp->h_addrtype == AF_INET && hp->h_length == 4)
66438ad259dSeric 		{
66538ad259dSeric 			register int i;
66638ad259dSeric 
66738ad259dSeric 			for (i = 0; i < MAXIPADDR; i++)
66838ad259dSeric 			{
66938ad259dSeric 				if (hp->h_addr_list[i] == NULL)
67038ad259dSeric 					break;
67138ad259dSeric 				MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
67238ad259dSeric 			}
67338ad259dSeric 			MyIpAddrs[i].s_addr = 0;
67438ad259dSeric 		}
67538ad259dSeric 
676a44d5a5eSeric 		return (hp->h_aliases);
6777364df9fSeric 	}
678444eaf03Seric 	else
679444eaf03Seric 		return (NULL);
680444eaf03Seric }
681cb452edcSeric /*
682320e0d1cSeric **  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
683320e0d1cSeric **
684320e0d1cSeric **	Parameters:
685320e0d1cSeric **		fd -- the descriptor
686320e0d1cSeric **
687320e0d1cSeric **	Returns:
688320e0d1cSeric **		The host name associated with this descriptor, if it can
689320e0d1cSeric **			be determined.
690320e0d1cSeric **		NULL otherwise.
691320e0d1cSeric **
692320e0d1cSeric **	Side Effects:
693320e0d1cSeric **		none
694320e0d1cSeric */
695320e0d1cSeric 
696320e0d1cSeric char *
697320e0d1cSeric getrealhostname(fd)
698320e0d1cSeric 	int fd;
699320e0d1cSeric {
700320e0d1cSeric 	register struct hostent *hp;
701e4a929e2Seric 	SOCKADDR sa;
702e2f2f828Seric 	int salen;
703320e0d1cSeric 	char hbuf[MAXNAME];
704320e0d1cSeric 	extern struct hostent *gethostbyaddr();
705320e0d1cSeric 
706e2f2f828Seric 	salen = sizeof sa;
70725f5a145Seric 	if (getsockname(fd, &sa.sa, &salen) < 0 || salen <= 0)
708320e0d1cSeric 		return NULL;
70925f5a145Seric 	hp = gethostbyaddr(sa.sa.sa_data, salen, sa.sa.sa_family);
710320e0d1cSeric 	if (hp != NULL)
711320e0d1cSeric 		(void) strcpy(hbuf, hp->h_name);
712320e0d1cSeric 	else
713e2f2f828Seric 		(void) sprintf(hbuf, "[%s]", anynet_ntoa(&sa));
714320e0d1cSeric 	return hbuf;
715320e0d1cSeric }
716320e0d1cSeric /*
71715d084d5Seric **  MAPHOSTNAME -- turn a hostname into canonical form
71815d084d5Seric **
71915d084d5Seric **	Parameters:
72005b57da8Seric **		map -- a pointer to this map (unused).
72115d084d5Seric **		hbuf -- a buffer containing a hostname.
72215d084d5Seric **		hbsize -- the size of hbuf.
723d798a1deSeric **		avp -- unused -- for compatibility with other mapping
724d798a1deSeric **			functions.
72515d084d5Seric **
72615d084d5Seric **	Returns:
72715d084d5Seric **		The mapping, if found.
72815d084d5Seric **		NULL if no mapping found.
72915d084d5Seric **
73015d084d5Seric **	Side Effects:
73115d084d5Seric **		Looks up the host specified in hbuf.  If it is not
73215d084d5Seric **		the canonical name for that host, return the canonical
73315d084d5Seric **		name.
734f36ede03Sbostic */
735cb452edcSeric 
73615d084d5Seric char *
73705b57da8Seric maphostname(map, hbuf, hbsize, avp)
73805b57da8Seric 	MAP *map;
73999f7cf32Seric 	char *hbuf;
74099f7cf32Seric 	int hbsize;
74115d084d5Seric 	char **avp;
74299f7cf32Seric {
74399f7cf32Seric 	register struct hostent *hp;
7445f78836eSmiriam 	u_long in_addr;
74505b57da8Seric 	char *cp;
74638ad259dSeric 	int i;
747f36ede03Sbostic 	struct hostent *gethostbyaddr();
7485f78836eSmiriam 
74999b358daSeric 	/* allow room for null */
75015d084d5Seric 	hbsize--;
75115d084d5Seric 
752f36ede03Sbostic 	/*
753f36ede03Sbostic 	 * If first character is a bracket, then it is an address
754f36ede03Sbostic 	 * lookup.  Address is copied into a temporary buffer to
755f36ede03Sbostic 	 * strip the brackets and to preserve hbuf if address is
756f36ede03Sbostic 	 * unknown.
757f36ede03Sbostic 	 */
75815d084d5Seric 
759cb452edcSeric 	if (*hbuf != '[')
76015d084d5Seric 	{
761d798a1deSeric 		extern bool getcanonname();
762d798a1deSeric 
7638cb4653dSeric 		if (tTd(9, 1))
7649040ec4fSeric 			printf("maphostname(%s, %d) => ", hbuf, hbsize);
765d5c60ac0Seric 		if (getcanonname(hbuf, hbsize))
7669040ec4fSeric 		{
7679040ec4fSeric 			if (tTd(9, 1))
7689040ec4fSeric 				printf("%s\n", hbuf);
76915d084d5Seric 			return hbuf;
7709040ec4fSeric 		}
77115d084d5Seric 		else
7729040ec4fSeric 		{
7739040ec4fSeric 			if (tTd(9, 1))
7749040ec4fSeric 				printf("FAIL\n");
77515d084d5Seric 			return NULL;
77615d084d5Seric 		}
7779040ec4fSeric 	}
77805b57da8Seric 	if ((cp = strchr(hbuf, ']')) == NULL)
77915d084d5Seric 		return (NULL);
78034e39927Sbostic 	*cp = '\0';
78105b57da8Seric 	in_addr = inet_addr(&hbuf[1]);
78238ad259dSeric 
78338ad259dSeric 	/* check to see if this is one of our addresses */
78438ad259dSeric 	for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
78538ad259dSeric 	{
78638ad259dSeric 		if (MyIpAddrs[i].s_addr == in_addr)
78738ad259dSeric 		{
78838ad259dSeric 			strncpy(hbuf, MyHostName, hbsize);
78938ad259dSeric 			hbuf[hbsize] = '\0';
79038ad259dSeric 			return hbuf;
79138ad259dSeric 		}
79238ad259dSeric 	}
79338ad259dSeric 
79438ad259dSeric 	/* nope -- ask the name server */
79531601fa7Seric 	hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
7965f78836eSmiriam 	if (hp == NULL)
79715d084d5Seric 		return (NULL);
79815d084d5Seric 
79938ad259dSeric 	/* found a match -- copy out */
80005b57da8Seric 	if (strlen(hp->h_name) > hbsize)
80105b57da8Seric 		hp->h_name[hbsize] = '\0';
802fefbbe29Seric 	(void) strcpy(hbuf, hp->h_name);
80315d084d5Seric 	return hbuf;
80499f7cf32Seric }
805e2f2f828Seric /*
806e2f2f828Seric **  ANYNET_NTOA -- convert a network address to printable form.
807e2f2f828Seric **
808e2f2f828Seric **	Parameters:
809e2f2f828Seric **		sap -- a pointer to a sockaddr structure.
810e2f2f828Seric **
811e2f2f828Seric **	Returns:
812e2f2f828Seric **		A printable version of that sockaddr.
813e2f2f828Seric */
814e2f2f828Seric 
815e2f2f828Seric char *
816e2f2f828Seric anynet_ntoa(sap)
817e2f2f828Seric 	register SOCKADDR *sap;
818e2f2f828Seric {
819e2f2f828Seric 	register char *bp;
820e2f2f828Seric 	register char *ap;
821e2f2f828Seric 	int l;
822e2f2f828Seric 	static char buf[80];
823e2f2f828Seric 
8248cb4653dSeric 	/* check for null/zero family */
8258cb4653dSeric 	if (sap == NULL)
8268cb4653dSeric 		return "NULLADDR";
8278cb4653dSeric 	if (sap->sa.sa_family == 0)
8288cb4653dSeric 		return "0";
8298cb4653dSeric 
83083c1f4bcSeric #ifdef NETINET
83183c1f4bcSeric 	if (sap->sa.sa_family == AF_INET)
832e2f2f828Seric 	{
833e2f2f828Seric 		extern char *inet_ntoa();
834e2f2f828Seric 
835e2f2f828Seric 		return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
836e2f2f828Seric 	}
83783c1f4bcSeric #endif
838e2f2f828Seric 
839e2f2f828Seric 	/* unknown family -- just dump bytes */
84083c1f4bcSeric 	(void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
841e2f2f828Seric 	bp = &buf[strlen(buf)];
84283c1f4bcSeric 	ap = sap->sa.sa_data;
84383c1f4bcSeric 	for (l = sizeof sap->sa.sa_data; --l >= 0; )
844e2f2f828Seric 	{
845e2f2f828Seric 		(void) sprintf(bp, "%02x:", *ap++ & 0377);
846e2f2f828Seric 		bp += 3;
847e2f2f828Seric 	}
848e2f2f828Seric 	*--bp = '\0';
849e2f2f828Seric 	return buf;
850e2f2f828Seric }
851f36ede03Sbostic 
8526c2c3107Seric # else /* DAEMON */
85399f7cf32Seric /* code for systems without sophisticated networking */
854444eaf03Seric 
855444eaf03Seric /*
856444eaf03Seric **  MYHOSTNAME -- stub version for case of no daemon code.
85721e9914dSeric **
85821e9914dSeric **	Can't convert to upper case here because might be a UUCP name.
859897f1869Seric **
860897f1869Seric **	Mark, you can change this to be anything you want......
861444eaf03Seric */
862444eaf03Seric 
863444eaf03Seric char **
864897f1869Seric myhostname(hostbuf, size)
865444eaf03Seric 	char hostbuf[];
866897f1869Seric 	int size;
867444eaf03Seric {
868444eaf03Seric 	register FILE *f;
869444eaf03Seric 
870444eaf03Seric 	hostbuf[0] = '\0';
871444eaf03Seric 	f = fopen("/usr/include/whoami", "r");
872444eaf03Seric 	if (f != NULL)
873444eaf03Seric 	{
874897f1869Seric 		(void) fgets(hostbuf, size, f);
875444eaf03Seric 		fixcrlf(hostbuf, TRUE);
876444eaf03Seric 		(void) fclose(f);
877444eaf03Seric 	}
878444eaf03Seric 	return (NULL);
879444eaf03Seric }
88099f7cf32Seric /*
881320e0d1cSeric **  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
882320e0d1cSeric **
883320e0d1cSeric **	Parameters:
884320e0d1cSeric **		fd -- the descriptor
885320e0d1cSeric **
886320e0d1cSeric **	Returns:
887320e0d1cSeric **		The host name associated with this descriptor, if it can
888320e0d1cSeric **			be determined.
889320e0d1cSeric **		NULL otherwise.
890320e0d1cSeric **
891320e0d1cSeric **	Side Effects:
892320e0d1cSeric **		none
893320e0d1cSeric */
894320e0d1cSeric 
895320e0d1cSeric char *
896320e0d1cSeric getrealhostname(fd)
897320e0d1cSeric 	int fd;
898320e0d1cSeric {
899320e0d1cSeric 	return NULL;
900320e0d1cSeric }
901320e0d1cSeric /*
90299f7cf32Seric **  MAPHOSTNAME -- turn a hostname into canonical form
90399f7cf32Seric **
90499f7cf32Seric **	Parameters:
90505b57da8Seric **		map -- a pointer to the database map.
90699f7cf32Seric **		hbuf -- a buffer containing a hostname.
90715d084d5Seric **		avp -- a pointer to a (cf file defined) argument vector.
90899f7cf32Seric **
90999f7cf32Seric **	Returns:
91015d084d5Seric **		mapped host name
911cb452edcSeric **		FALSE otherwise.
91299f7cf32Seric **
91399f7cf32Seric **	Side Effects:
91499f7cf32Seric **		Looks up the host specified in hbuf.  If it is not
91599f7cf32Seric **		the canonical name for that host, replace it with
91699f7cf32Seric **		the canonical name.  If the name is unknown, or it
91799f7cf32Seric **		is already the canonical name, leave it unchanged.
91899f7cf32Seric */
91999f7cf32Seric 
92099f7cf32Seric /*ARGSUSED*/
92115d084d5Seric char *
92205b57da8Seric maphostname(map, hbuf, hbsize, avp)
92305b57da8Seric 	MAP *map;
92499f7cf32Seric 	char *hbuf;
92599f7cf32Seric 	int hbsize;
92615d084d5Seric 	char **avp;
92799f7cf32Seric {
92815d084d5Seric 	return NULL;
92999f7cf32Seric }
93099f7cf32Seric 
9316c2c3107Seric #endif /* DAEMON */
932