xref: /original-bsd/usr.sbin/sendmail/src/daemon.c (revision 850144ca)
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*850144caSeric static char sccsid[] = "@(#)daemon.c	6.29 (Berkeley) 03/30/93 (with daemon mode)";
16d0a9e852Seric #else
17*850144caSeric static char sccsid[] = "@(#)daemon.c	6.29 (Berkeley) 03/30/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 
277fa39d90Seric /*
287fa39d90Seric **  DAEMON.C -- routines to use when running as a daemon.
2947b12ae1Seric **
3047b12ae1Seric **	This entire file is highly dependent on the 4.2 BSD
3147b12ae1Seric **	interprocess communication primitives.  No attempt has
3247b12ae1Seric **	been made to make this file portable to Version 7,
3347b12ae1Seric **	Version 6, MPX files, etc.  If you should try such a
3447b12ae1Seric **	thing yourself, I recommend chucking the entire file
3547b12ae1Seric **	and starting from scratch.  Basic semantics are:
3647b12ae1Seric **
3747b12ae1Seric **	getrequests()
3847b12ae1Seric **		Opens a port and initiates a connection.
3947b12ae1Seric **		Returns in a child.  Must set InChannel and
4047b12ae1Seric **		OutChannel appropriately.
41b7d7afcbSeric **	clrdaemon()
42b7d7afcbSeric **		Close any open files associated with getting
43b7d7afcbSeric **		the connection; this is used when running the queue,
44b7d7afcbSeric **		etc., to avoid having extra file descriptors during
45b7d7afcbSeric **		the queue run and to avoid confusing the network
46b7d7afcbSeric **		code (if it cares).
47914346b1Seric **	makeconnection(host, port, outfile, infile, usesecureport)
4847b12ae1Seric **		Make a connection to the named host on the given
4947b12ae1Seric **		port.  Set *outfile and *infile to the files
5047b12ae1Seric **		appropriate for communication.  Returns zero on
5147b12ae1Seric **		success, else an exit status describing the
5247b12ae1Seric **		error.
5305b57da8Seric **	maphostname(map, hbuf, hbufsiz, avp)
5405b57da8Seric **		Convert the entry in hbuf into a canonical form.
557fa39d90Seric */
56e2f2f828Seric 
57e2f2f828Seric extern char	*anynet_ntoa();
587fa39d90Seric /*
597fa39d90Seric **  GETREQUESTS -- open mail IPC port and get requests.
607fa39d90Seric **
617fa39d90Seric **	Parameters:
627fa39d90Seric **		none.
637fa39d90Seric **
647fa39d90Seric **	Returns:
657fa39d90Seric **		none.
667fa39d90Seric **
677fa39d90Seric **	Side Effects:
687fa39d90Seric **		Waits until some interesting activity occurs.  When
697fa39d90Seric **		it does, a child is created to process it, and the
707fa39d90Seric **		parent waits for completion.  Return from this
71147303b1Seric **		routine is always in the child.  The file pointers
72147303b1Seric **		"InChannel" and "OutChannel" should be set to point
73147303b1Seric **		to the communication channel.
747fa39d90Seric */
757fa39d90Seric 
76b7d7afcbSeric int		DaemonSocket	= -1;		/* fd describing socket */
77bfb80540Seric SOCKADDR	DaemonAddr;			/* socket for incoming */
781c71e510Seric 
797fa39d90Seric getrequests()
807fa39d90Seric {
811c71e510Seric 	int t;
821c71e510Seric 	register struct servent *sp;
837868dfc2Seric 	int on = 1;
8415d084d5Seric 	bool refusingconnections = TRUE;
850aae1086Seric 	FILE *pidf;
869b100374Sbostic 	extern void reapchild();
87eb889047Seric 
88a8268164Seric 	/*
891c71e510Seric 	**  Set up the address for the mailer.
90eb889047Seric 	*/
91eb889047Seric 
92bfb80540Seric 	if (DaemonAddr.sin.sin_family == 0)
93bfb80540Seric 		DaemonAddr.sin.sin_family = AF_INET;
94bfb80540Seric 	if (DaemonAddr.sin.sin_addr.s_addr == 0)
95bfb80540Seric 		DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
96bfb80540Seric 	if (DaemonAddr.sin.sin_port == 0)
97bfb80540Seric 	{
981c71e510Seric 		sp = getservbyname("smtp", "tcp");
991c71e510Seric 		if (sp == NULL)
100d0a9e852Seric 		{
10108b25121Seric 			syserr("554 server \"smtp\" unknown");
102a1961f2aSeric 			goto severe;
1031c71e510Seric 		}
104bfb80540Seric 		DaemonAddr.sin.sin_port = sp->s_port;
105bfb80540Seric 	}
1061c71e510Seric 
1071c71e510Seric 	/*
1081c71e510Seric 	**  Try to actually open the connection.
1091c71e510Seric 	*/
1101c71e510Seric 
1111c71e510Seric 	if (tTd(15, 1))
112bfb80540Seric 		printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
1131c71e510Seric 
1141c71e510Seric 	/* get a socket for the SMTP connection */
115af5e902cSeric 	DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
116b7d7afcbSeric 	if (DaemonSocket < 0)
1171c71e510Seric 	{
1181c71e510Seric 		/* probably another daemon already */
1191c71e510Seric 		syserr("getrequests: can't create socket");
1201c71e510Seric 	  severe:
121b0ba8827Seric # ifdef LOG
122b0ba8827Seric 		if (LogLevel > 0)
1230c034190Seric 			syslog(LOG_ALERT, "problem creating SMTP socket");
1246c2c3107Seric # endif /* LOG */
12547b12ae1Seric 		finis();
126d0a9e852Seric 	}
1271b6e4a15Seric 
1281b6e4a15Seric 	/* turn on network debugging? */
129a2ef5fa4Seric 	if (tTd(15, 101))
13052308a50Seric 		(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
1311b6e4a15Seric 
1327868dfc2Seric 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
1337868dfc2Seric 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
1347868dfc2Seric 
135bfb80540Seric 	if (bind(DaemonSocket, &DaemonAddr.sa, sizeof DaemonAddr) < 0)
1361c71e510Seric 	{
1371c71e510Seric 		syserr("getrequests: cannot bind");
138b7d7afcbSeric 		(void) close(DaemonSocket);
1391c71e510Seric 		goto severe;
1401c71e510Seric 	}
1411c71e510Seric 
1421cd247eeSeric 	(void) signal(SIGCHLD, reapchild);
14352308a50Seric 
1440aae1086Seric 	/* write the pid to the log file for posterity */
1450aae1086Seric 	pidf = fopen(PidFile, "w");
1460aae1086Seric 	if (pidf != NULL)
1470aae1086Seric 	{
1480aae1086Seric 		fprintf(pidf, "%d\n", getpid());
1490aae1086Seric 		fclose(pidf);
1500aae1086Seric 	}
1510aae1086Seric 
1520aae1086Seric 
1531c71e510Seric 	if (tTd(15, 1))
154b7d7afcbSeric 		printf("getrequests: %d\n", DaemonSocket);
1551c71e510Seric 
1561c71e510Seric 	for (;;)
1571c71e510Seric 	{
1583a099713Seric 		register int pid;
159a44d5a5eSeric 		auto int lotherend;
16015d084d5Seric 		extern bool refuseconnections();
1613a099713Seric 
1623a099713Seric 		/* see if we are rejecting connections */
16315d084d5Seric 		CurrentLA = getla();
16415d084d5Seric 		if (refuseconnections())
1656775ec03Sbostic 		{
16615d084d5Seric 			if (!refusingconnections)
16715d084d5Seric 			{
16815d084d5Seric 				/* don't queue so peer will fail quickly */
16915d084d5Seric 				(void) listen(DaemonSocket, 0);
17015d084d5Seric 				refusingconnections = TRUE;
17115d084d5Seric 			}
17271e5e267Seric 			setproctitle("rejecting connections: load average: %d",
17371e5e267Seric 				CurrentLA);
1743a099713Seric 			sleep(5);
17515d084d5Seric 			continue;
17615d084d5Seric 		}
17715d084d5Seric 
17815d084d5Seric 		if (refusingconnections)
17915d084d5Seric 		{
18015d084d5Seric 			/* start listening again */
18115d084d5Seric 			if (listen(DaemonSocket, 10) < 0)
18215d084d5Seric 			{
18315d084d5Seric 				syserr("getrequests: cannot listen");
18415d084d5Seric 				(void) close(DaemonSocket);
18515d084d5Seric 				goto severe;
18615d084d5Seric 			}
18715d084d5Seric 			setproctitle("accepting connections");
18815d084d5Seric 			refusingconnections = FALSE;
1896775ec03Sbostic 		}
190a44d5a5eSeric 
1911c71e510Seric 		/* wait for a connection */
1921c71e510Seric 		do
1931c71e510Seric 		{
1941c71e510Seric 			errno = 0;
1959f9a15b6Skarels 			lotherend = sizeof RealHostAddr;
1969b100374Sbostic 			t = accept(DaemonSocket,
1979b100374Sbostic 			    (struct sockaddr *)&RealHostAddr, &lotherend);
1981c71e510Seric 		} while (t < 0 && errno == EINTR);
1991c71e510Seric 		if (t < 0)
2001c71e510Seric 		{
2011c71e510Seric 			syserr("getrequests: accept");
2021c71e510Seric 			sleep(5);
2031c71e510Seric 			continue;
2041c71e510Seric 		}
205d0a9e852Seric 
206d0a9e852Seric 		/*
207d0a9e852Seric 		**  Create a subprocess to process the mail.
208d0a9e852Seric 		*/
209d0a9e852Seric 
21061e4310fSeric 		if (tTd(15, 2))
2111c71e510Seric 			printf("getrequests: forking (fd = %d)\n", t);
212eb889047Seric 
213a8268164Seric 		pid = fork();
214a8268164Seric 		if (pid < 0)
215a8268164Seric 		{
216a8268164Seric 			syserr("daemon: cannot fork");
217a8268164Seric 			sleep(10);
2181c71e510Seric 			(void) close(t);
219a8268164Seric 			continue;
220a8268164Seric 		}
221a8268164Seric 
222a8268164Seric 		if (pid == 0)
223a8268164Seric 		{
224a44d5a5eSeric 			extern struct hostent *gethostbyaddr();
225a44d5a5eSeric 			register struct hostent *hp;
226a44d5a5eSeric 			char buf[MAXNAME];
227a44d5a5eSeric 
228a8268164Seric 			/*
229a8268164Seric 			**  CHILD -- return to caller.
230a44d5a5eSeric 			**	Collect verified idea of sending host.
231a8268164Seric 			**	Verify calling user id if possible here.
232a8268164Seric 			*/
233a8268164Seric 
2341cd247eeSeric 			(void) signal(SIGCHLD, SIG_DFL);
235779ac194Seric 
236a44d5a5eSeric 			/* determine host name */
23783c1f4bcSeric 			switch (RealHostAddr.sa.sa_family)
23883c1f4bcSeric 			{
23983c1f4bcSeric #ifdef NETINET
24083c1f4bcSeric 			  case AF_INET:
24183c1f4bcSeric 				hp = gethostbyaddr((char *) &RealHostAddr.sin.sin_addr,
24283c1f4bcSeric 					sizeof RealHostAddr.sin.sin_addr,
24383c1f4bcSeric 					AF_INET);
24483c1f4bcSeric 				break;
24583c1f4bcSeric #endif
24683c1f4bcSeric 
24783c1f4bcSeric #ifdef NETISO
24883c1f4bcSeric 			  case AF_ISO:
24983c1f4bcSeric 				hp = gethostbyaddr((char *) &RealHostAddr.siso.siso_addr,
25083c1f4bcSeric 					sizeof RealHostAddr.siso.siso_addr,
25183c1f4bcSeric 					AF_ISO);
25283c1f4bcSeric 				break;
25383c1f4bcSeric #endif
25483c1f4bcSeric 
25583c1f4bcSeric 			  default:
25683c1f4bcSeric 				hp = gethostbyaddr(RealHostAddr.sa.sa_data,
25783c1f4bcSeric 					   sizeof RealHostAddr.sa.sa_data,
25883c1f4bcSeric 					   RealHostAddr.sa.sa_family);
25983c1f4bcSeric 				break;
26083c1f4bcSeric 			}
26183c1f4bcSeric 
262a44d5a5eSeric 			if (hp != NULL)
263fefbbe29Seric 				(void) strcpy(buf, hp->h_name);
264a44d5a5eSeric 			else
26529dcf4baSeric 			{
26629dcf4baSeric 				/* produce a dotted quad */
26729dcf4baSeric 				(void) sprintf(buf, "[%s]",
268e2f2f828Seric 					anynet_ntoa(&RealHostAddr));
26929dcf4baSeric 			}
27029dcf4baSeric 
2712a6bc25bSeric #ifdef LOG
272845e533cSeric 			if (LogLevel > 10)
2732a6bc25bSeric 			{
2742a6bc25bSeric 				/* log connection information */
2752a6bc25bSeric 				syslog(LOG_INFO, "connect from %s (%s)",
276e2f2f828Seric 					buf, anynet_ntoa(&RealHostAddr));
2772a6bc25bSeric 			}
2782a6bc25bSeric #endif
2792a6bc25bSeric 
28029dcf4baSeric 			/* should we check for illegal connection here? XXX */
28129dcf4baSeric 
282a44d5a5eSeric 			RealHostName = newstr(buf);
283a44d5a5eSeric 
284b7d7afcbSeric 			(void) close(DaemonSocket);
2851c71e510Seric 			InChannel = fdopen(t, "r");
2861d5bd586Seric 			OutChannel = fdopen(dup(t), "w");
28761e4310fSeric 			if (tTd(15, 2))
288d0a9e852Seric 				printf("getreq: returning\n");
289a8268164Seric 			return;
290a8268164Seric 		}
291a8268164Seric 
2923c154354Seric 		/* close the port so that others will hang (for a while) */
2933c154354Seric 		(void) close(t);
2948e3e4b17Seric 	}
2953c154354Seric 	/*NOTREACHED*/
2963c154354Seric }
2978e3e4b17Seric /*
298b7d7afcbSeric **  CLRDAEMON -- reset the daemon connection
299b7d7afcbSeric **
300b7d7afcbSeric **	Parameters:
301b7d7afcbSeric **		none.
302b7d7afcbSeric **
303b7d7afcbSeric **	Returns:
304b7d7afcbSeric **		none.
305b7d7afcbSeric **
306b7d7afcbSeric **	Side Effects:
307b7d7afcbSeric **		releases any resources used by the passive daemon.
308b7d7afcbSeric */
309b7d7afcbSeric 
310b7d7afcbSeric clrdaemon()
311b7d7afcbSeric {
312b7d7afcbSeric 	if (DaemonSocket >= 0)
313b7d7afcbSeric 		(void) close(DaemonSocket);
314b7d7afcbSeric 	DaemonSocket = -1;
315b7d7afcbSeric }
316b7d7afcbSeric /*
317bfb80540Seric **  SETDAEMONOPTIONS -- set options for running the daemon
318bfb80540Seric **
319bfb80540Seric **	Parameters:
320bfb80540Seric **		p -- the options line.
321bfb80540Seric **
322bfb80540Seric **	Returns:
323bfb80540Seric **		none.
324bfb80540Seric */
325bfb80540Seric 
326bfb80540Seric setdaemonoptions(p)
327bfb80540Seric 	register char *p;
328bfb80540Seric {
329*850144caSeric 	if (DaemonAddr.sa.sa_family == AF_UNSPEC)
330*850144caSeric 		DaemonAddr.sa.sa_family = AF_INET;
331*850144caSeric 
332bfb80540Seric 	while (p != NULL)
333bfb80540Seric 	{
334bfb80540Seric 		register char *f;
335bfb80540Seric 		register char *v;
336bfb80540Seric 
337bfb80540Seric 		while (isascii(*p) && isspace(*p))
338bfb80540Seric 			p++;
339bfb80540Seric 		if (*p == '\0')
340bfb80540Seric 			break;
341bfb80540Seric 		f = p;
342bfb80540Seric 		p = strchr(p, ',');
343bfb80540Seric 		if (p != NULL)
344bfb80540Seric 			*p++ = '\0';
345bfb80540Seric 		v = strchr(f, '=');
346bfb80540Seric 		if (v == NULL)
347bfb80540Seric 			continue;
348bfb80540Seric 		while (isascii(*++v) && isspace(*v))
349bfb80540Seric 			continue;
350bfb80540Seric 
351bfb80540Seric 		switch (*f)
352bfb80540Seric 		{
353*850144caSeric 		  case 'F':		/* address family */
354*850144caSeric 			if (isascii(*v) && isdigit(*v))
355*850144caSeric 				DaemonAddr.sa.sa_family = atoi(v);
356*850144caSeric #ifdef NETINET
357*850144caSeric 			else if (strcasecmp(v, "inet") == 0)
358*850144caSeric 				DaemonAddr.sa.sa_family = AF_INET;
359*850144caSeric #endif
360*850144caSeric #ifdef NETISO
361*850144caSeric 			else if (strcasecmp(v, "iso") == 0)
362*850144caSeric 				DaemonAddr.sa.sa_family = AF_ISO;
363*850144caSeric #endif
364*850144caSeric #ifdef NETNS
365*850144caSeric 			else if (strcasecmp(v, "ns") == 0)
366*850144caSeric 				DaemonAddr.sa.sa_family = AF_NS;
367*850144caSeric #endif
368*850144caSeric #ifdef NETX25
369*850144caSeric 			else if (strcasecmp(v, "x.25") == 0)
370*850144caSeric 				DaemonAddr.sa.sa_family = AF_CCITT;
371*850144caSeric #endif
372*850144caSeric 			else
373*850144caSeric 				syserr("554 Unknown address family %s in Family=option", v);
374*850144caSeric 			break;
375*850144caSeric 
376*850144caSeric 		  case 'A':		/* address */
377*850144caSeric 			switch (DaemonAddr.sa.sa_family)
378*850144caSeric 			{
379*850144caSeric #ifdef NETINET
380*850144caSeric 			  case AF_INET:
381*850144caSeric 				if (isascii(*v) && isdigit(*v))
382*850144caSeric 					DaemonAddr.sin.sin_addr.s_addr = inet_network(v);
383*850144caSeric 				else
384*850144caSeric 				{
385*850144caSeric 					register struct netent *np;
386*850144caSeric 
387*850144caSeric 					np = getnetbyname(v);
388*850144caSeric 					if (np == NULL)
389*850144caSeric 						syserr("554 network \"%s\" unknown", v);
390*850144caSeric 					else
391*850144caSeric 						DaemonAddr.sin.sin_addr.s_addr = np->n_net;
392*850144caSeric 				}
393*850144caSeric 				break;
394*850144caSeric #endif
395*850144caSeric 
396*850144caSeric 			  default:
397*850144caSeric 				syserr("554 Address= option unsupported for family %d",
398*850144caSeric 					DaemonAddr.sa.sa_family);
399*850144caSeric 				break;
400*850144caSeric 			}
401*850144caSeric 			break;
402*850144caSeric 
403bfb80540Seric 		  case 'P':		/* port */
404*850144caSeric 			switch (DaemonAddr.sa.sa_family)
405*850144caSeric 			{
406*850144caSeric 				short port;
407*850144caSeric 
408*850144caSeric #ifdef NETINET
409*850144caSeric 			  case AF_INET:
410bfb80540Seric 				if (isascii(*v) && isdigit(*v))
411bfb80540Seric 					DaemonAddr.sin.sin_port = atoi(v);
412bfb80540Seric 				else
413bfb80540Seric 				{
414bfb80540Seric 					register struct servent *sp;
415bfb80540Seric 
416bfb80540Seric 					sp = getservbyname(v, "tcp");
417bfb80540Seric 					if (sp == NULL)
418bfb80540Seric 						syserr("554 server \"%s\" unknown", v);
419bfb80540Seric 					else
420bfb80540Seric 						DaemonAddr.sin.sin_port = sp->s_port;
421bfb80540Seric 				}
422bfb80540Seric 				break;
423*850144caSeric #endif
424bfb80540Seric 
425*850144caSeric #ifdef NETISO
426*850144caSeric 			  case AF_ISO:
427*850144caSeric 				/* assume two byte transport selector */
428bfb80540Seric 				if (isascii(*v) && isdigit(*v))
429*850144caSeric 					port = atoi(v);
430bfb80540Seric 				else
431bfb80540Seric 				{
432*850144caSeric 					register struct servent *sp;
433bfb80540Seric 
434*850144caSeric 					sp = getservbyname(v, "tcp");
435*850144caSeric 					if (sp == NULL)
436*850144caSeric 						syserr("554 server \"%s\" unknown", v);
437bfb80540Seric 					else
438*850144caSeric 						port = sp->s_port;
439*850144caSeric 				}
440*850144caSeric 				bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
441*850144caSeric 				break;
442*850144caSeric #endif
443*850144caSeric 
444*850144caSeric 			  default:
445*850144caSeric 				syserr("554 Port= option unsupported for family %d",
446*850144caSeric 					DaemonAddr.sa.sa_family);
447*850144caSeric 				break;
448bfb80540Seric 			}
449bfb80540Seric 			break;
450bfb80540Seric 		}
451bfb80540Seric 	}
452bfb80540Seric }
453bfb80540Seric /*
4547aa493c5Seric **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
4557aa493c5Seric **
4567aa493c5Seric **	Parameters:
4577aa493c5Seric **		host -- the name of the host.
45848ff0a9dSeric **		port -- the port number to connect to.
459655feedbSeric **		mci -- a pointer to the mail connection information
460655feedbSeric **			structure to be filled in.
461914346b1Seric **		usesecureport -- if set, use a low numbered (reserved)
462914346b1Seric **			port to provide some rudimentary authentication.
4637aa493c5Seric **
4647aa493c5Seric **	Returns:
4657aa493c5Seric **		An exit code telling whether the connection could be
4667aa493c5Seric **			made and if not why not.
4677aa493c5Seric **
4687aa493c5Seric **	Side Effects:
4697aa493c5Seric **		none.
4707aa493c5Seric */
4717aa493c5Seric 
472e2f2f828Seric SOCKADDR	CurHostAddr;		/* address of current host */
47371ff6caaSeric 
474b31e7f2bSeric int
475655feedbSeric makeconnection(host, port, mci, usesecureport)
4767aa493c5Seric 	char *host;
477210215eaSeric 	u_short port;
478b31e7f2bSeric 	register MCI *mci;
479914346b1Seric 	bool usesecureport;
4807aa493c5Seric {
48104344589Sbloom 	register int i, s;
48204344589Sbloom 	register struct hostent *hp = (struct hostent *)NULL;
483e2f2f828Seric 	SOCKADDR addr;
4846286bb75Sbloom 	int sav_errno;
485e2f2f828Seric 	int addrlen;
486134746fbSeric #ifdef NAMED_BIND
487134746fbSeric 	extern int h_errno;
488134746fbSeric #endif
4897aa493c5Seric 
4907aa493c5Seric 	/*
4917aa493c5Seric 	**  Set up the address for the mailer.
49271096d12Seric 	**	Accept "[a.b.c.d]" syntax for host name.
4937aa493c5Seric 	*/
4947aa493c5Seric 
495134746fbSeric #ifdef NAMED_BIND
496794bdbb9Smiriam 	h_errno = 0;
497134746fbSeric #endif
498794bdbb9Smiriam 	errno = 0;
499967778e2Seric 	bzero(&CurHostAddr, sizeof CurHostAddr);
500794bdbb9Smiriam 
50171096d12Seric 	if (host[0] == '[')
50271096d12Seric 	{
503a44d5a5eSeric 		long hid;
5046c2c3107Seric 		register char *p = strchr(host, ']');
50571096d12Seric 
506a44d5a5eSeric 		if (p != NULL)
50771096d12Seric 		{
508a44d5a5eSeric 			*p = '\0';
509a44d5a5eSeric 			hid = inet_addr(&host[1]);
510a7e21fe6Seric 			if (hid == -1)
511a7e21fe6Seric 			{
512a7e21fe6Seric 				/* try it as a host name (avoid MX lookup) */
513a7e21fe6Seric 				hp = gethostbyname(&host[1]);
514a7e21fe6Seric 				*p = ']';
515a7e21fe6Seric 				goto gothostent;
516a7e21fe6Seric 			}
517a44d5a5eSeric 			*p = ']';
51871096d12Seric 		}
519a7e21fe6Seric 		if (p == NULL)
52071096d12Seric 		{
52108b25121Seric 			usrerr("553 Invalid numeric domain spec \"%s\"", host);
52271096d12Seric 			return (EX_NOHOST);
52371096d12Seric 		}
52483c1f4bcSeric 		addr.sin.sin_family = AF_INET;
52583c1f4bcSeric 		addr.sin.sin_addr.s_addr = hid;
52671096d12Seric 	}
5271c71e510Seric 	else
5281c71e510Seric 	{
52904344589Sbloom 		hp = gethostbyname(host);
530a7e21fe6Seric gothostent:
531794bdbb9Smiriam 		if (hp == NULL)
532794bdbb9Smiriam 		{
533134746fbSeric #ifdef NAMED_BIND
534794bdbb9Smiriam 			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
53552308a50Seric 				return (EX_TEMPFAIL);
53682e5d8ddSeric 
537134746fbSeric 			/* if name server is specified, assume temp fail */
538134746fbSeric 			if (errno == ECONNREFUSED && UseNameServer)
539134746fbSeric 				return (EX_TEMPFAIL);
540134746fbSeric #endif
5417aa493c5Seric 			return (EX_NOHOST);
542794bdbb9Smiriam 		}
54383c1f4bcSeric 		addr.sa.sa_family = hp->h_addrtype;
54483c1f4bcSeric 		switch (hp->h_addrtype)
54583c1f4bcSeric 		{
54683c1f4bcSeric #ifdef NETINET
54783c1f4bcSeric 		  case AF_INET:
548e2f2f828Seric 			bcopy(hp->h_addr,
54983c1f4bcSeric 				&addr.sin.sin_addr,
550e2f2f828Seric 				hp->h_length);
55183c1f4bcSeric 			break;
55283c1f4bcSeric #endif
55383c1f4bcSeric 
55483c1f4bcSeric 		  default:
555e2f2f828Seric 			bcopy(hp->h_addr,
55683c1f4bcSeric 				addr.sa.sa_data,
557e2f2f828Seric 				hp->h_length);
55883c1f4bcSeric 			break;
55983c1f4bcSeric 		}
56004344589Sbloom 		i = 1;
5611c71e510Seric 	}
5621c71e510Seric 
5631c71e510Seric 	/*
5641c71e510Seric 	**  Determine the port number.
5651c71e510Seric 	*/
5661c71e510Seric 
567fd7c0790Seric 	if (port != 0)
568e2f2f828Seric 		port = htons(port);
569fd7c0790Seric 	else
5701c71e510Seric 	{
5711c71e510Seric 		register struct servent *sp = getservbyname("smtp", "tcp");
5721c71e510Seric 
5731c71e510Seric 		if (sp == NULL)
5741c71e510Seric 		{
57508b25121Seric 			syserr("554 makeconnection: server \"smtp\" unknown");
576845e533cSeric 			return (EX_OSERR);
5771c71e510Seric 		}
578e2f2f828Seric 		port = sp->s_port;
579e2f2f828Seric 	}
580e2f2f828Seric 
58183c1f4bcSeric 	switch (addr.sa.sa_family)
582e2f2f828Seric 	{
583e2f2f828Seric 	  case AF_INET:
58483c1f4bcSeric 		addr.sin.sin_port = port;
585e2f2f828Seric 		addrlen = sizeof (struct sockaddr_in);
586e2f2f828Seric 		break;
587e2f2f828Seric 
588e2f2f828Seric #ifdef NETISO
589e2f2f828Seric 	  case AF_ISO:
590e2f2f828Seric 		/* assume two byte transport selector */
591e2f2f828Seric 		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
592e2f2f828Seric 		addrlen = sizeof (struct sockaddr_iso);
593e2f2f828Seric 		break;
594e2f2f828Seric #endif
595e2f2f828Seric 
596e2f2f828Seric 	  default:
59783c1f4bcSeric 		syserr("Can't connect to address family %d", addr.sa.sa_family);
598e2f2f828Seric 		return (EX_NOHOST);
5991c71e510Seric 	}
6007aa493c5Seric 
6017aa493c5Seric 	/*
6027aa493c5Seric 	**  Try to actually open the connection.
6037aa493c5Seric 	*/
6047aa493c5Seric 
605aea02ca1Seric 	for (;;)
606aea02ca1Seric 	{
60761e4310fSeric 		if (tTd(16, 1))
608e2f2f828Seric 			printf("makeconnection (%s [%s])\n",
609e2f2f828Seric 				host, anynet_ntoa(&addr));
6107aa493c5Seric 
611226e3022Seric 		/* save for logging */
612226e3022Seric 		CurHostAddr = addr;
613226e3022Seric 
614914346b1Seric 		if (usesecureport)
615914346b1Seric 		{
616914346b1Seric 			int rport = IPPORT_RESERVED - 1;
617914346b1Seric 
618914346b1Seric 			s = rresvport(&rport);
619914346b1Seric 		}
620914346b1Seric 		else
621914346b1Seric 		{
622af5e902cSeric 			s = socket(AF_INET, SOCK_STREAM, 0);
623914346b1Seric 		}
6247aa493c5Seric 		if (s < 0)
6257aa493c5Seric 		{
6266286bb75Sbloom 			sav_errno = errno;
627914346b1Seric 			syserr("makeconnection: no socket");
6287aa493c5Seric 			goto failure;
6297aa493c5Seric 		}
6307aa493c5Seric 
63161e4310fSeric 		if (tTd(16, 1))
632b31e7f2bSeric 			printf("makeconnection: fd=%d\n", s);
6331b6e4a15Seric 
6341b6e4a15Seric 		/* turn on network debugging? */
635a2ef5fa4Seric 		if (tTd(16, 101))
63652308a50Seric 		{
63752308a50Seric 			int on = 1;
638aea02ca1Seric 			(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
639aea02ca1Seric 					  (char *)&on, sizeof on);
64052308a50Seric 		}
64187d6e633Srick 		if (CurEnv->e_xfp != NULL)
642877a6142Seric 			(void) fflush(CurEnv->e_xfp);		/* for debugging */
6434bd6a662Seric 		errno = 0;					/* for debugging */
644e2f2f828Seric 		if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
645aea02ca1Seric 			break;
646aea02ca1Seric 
647aea02ca1Seric 		/* couldn't connect.... figure out why */
6486286bb75Sbloom 		sav_errno = errno;
6496286bb75Sbloom 		(void) close(s);
65004344589Sbloom 		if (hp && hp->h_addr_list[i])
65104344589Sbloom 		{
652e2f2f828Seric 			extern char *errstring();
653e2f2f828Seric 
654aea02ca1Seric 			if (tTd(16, 1))
655e2f2f828Seric 				printf("Connect failed (%s); trying new address....\n",
656e2f2f828Seric 					errstring(sav_errno));
65783c1f4bcSeric 			switch (addr.sa.sa_family)
65883c1f4bcSeric 			{
65983c1f4bcSeric #ifdef NETINET
66083c1f4bcSeric 			  case AF_INET:
661e2f2f828Seric 				bcopy(hp->h_addr_list[i++],
66283c1f4bcSeric 				      &addr.sin.sin_addr,
663e2f2f828Seric 				      hp->h_length);
66483c1f4bcSeric 				break;
66583c1f4bcSeric #endif
66683c1f4bcSeric 
66783c1f4bcSeric 			  default:
668e2f2f828Seric 				bcopy(hp->h_addr_list[i++],
66983c1f4bcSeric 					addr.sa.sa_data,
670914346b1Seric 					hp->h_length);
67183c1f4bcSeric 				break;
67283c1f4bcSeric 			}
673aea02ca1Seric 			continue;
67404344589Sbloom 		}
67504344589Sbloom 
6767aa493c5Seric 		/* failure, decide if temporary or not */
6777aa493c5Seric 	failure:
678e2de2524Seric 		if (transienterror(sav_errno))
679e2de2524Seric 			return EX_TEMPFAIL;
680e2de2524Seric 		else
68187d6e633Srick 		{
68287d6e633Srick 			extern char *errstring();
68387d6e633Srick 
68408b25121Seric 			message("%s", errstring(sav_errno));
6857aa493c5Seric 			return (EX_UNAVAILABLE);
6867aa493c5Seric 		}
6877aa493c5Seric 	}
6887aa493c5Seric 
6897aa493c5Seric 	/* connection ok, put it into canonical form */
690655feedbSeric 	mci->mci_out = fdopen(s, "w");
691655feedbSeric 	mci->mci_in = fdopen(dup(s), "r");
6927aa493c5Seric 
693dca8e1f7Seric 	return (EX_OK);
6947aa493c5Seric }
695444eaf03Seric /*
696444eaf03Seric **  MYHOSTNAME -- return the name of this host.
697444eaf03Seric **
698444eaf03Seric **	Parameters:
699444eaf03Seric **		hostbuf -- a place to return the name of this host.
700897f1869Seric **		size -- the size of hostbuf.
701444eaf03Seric **
702444eaf03Seric **	Returns:
703444eaf03Seric **		A list of aliases for this host.
704444eaf03Seric **
705444eaf03Seric **	Side Effects:
70638ad259dSeric **		Sets the MyIpAddrs buffer to a list of my IP addresses.
707444eaf03Seric */
708444eaf03Seric 
70938ad259dSeric struct in_addr	MyIpAddrs[MAXIPADDR + 1];
71038ad259dSeric 
711444eaf03Seric char **
712897f1869Seric myhostname(hostbuf, size)
713444eaf03Seric 	char hostbuf[];
714897f1869Seric 	int size;
715444eaf03Seric {
71638ad259dSeric 	register struct hostent *hp;
717444eaf03Seric 	extern struct hostent *gethostbyname();
718444eaf03Seric 
719af5e902cSeric 	if (gethostname(hostbuf, size) < 0)
720af5e902cSeric 	{
721af5e902cSeric 		(void) strcpy(hostbuf, "localhost");
722af5e902cSeric 	}
723a44d5a5eSeric 	hp = gethostbyname(hostbuf);
724a44d5a5eSeric 	if (hp != NULL)
7257364df9fSeric 	{
72638ad259dSeric 		(void) strncpy(hostbuf, hp->h_name, size - 1);
72738ad259dSeric 		hostbuf[size - 1] = '\0';
72838ad259dSeric 
72938ad259dSeric 		if (hp->h_addrtype == AF_INET && hp->h_length == 4)
73038ad259dSeric 		{
73138ad259dSeric 			register int i;
73238ad259dSeric 
73338ad259dSeric 			for (i = 0; i < MAXIPADDR; i++)
73438ad259dSeric 			{
73538ad259dSeric 				if (hp->h_addr_list[i] == NULL)
73638ad259dSeric 					break;
73738ad259dSeric 				MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
73838ad259dSeric 			}
73938ad259dSeric 			MyIpAddrs[i].s_addr = 0;
74038ad259dSeric 		}
74138ad259dSeric 
742a44d5a5eSeric 		return (hp->h_aliases);
7437364df9fSeric 	}
744444eaf03Seric 	else
745444eaf03Seric 		return (NULL);
746444eaf03Seric }
747cb452edcSeric /*
748320e0d1cSeric **  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
749320e0d1cSeric **
750320e0d1cSeric **	Parameters:
751320e0d1cSeric **		fd -- the descriptor
752320e0d1cSeric **
753320e0d1cSeric **	Returns:
754320e0d1cSeric **		The host name associated with this descriptor, if it can
755320e0d1cSeric **			be determined.
756320e0d1cSeric **		NULL otherwise.
757320e0d1cSeric **
758320e0d1cSeric **	Side Effects:
759320e0d1cSeric **		none
760320e0d1cSeric */
761320e0d1cSeric 
762320e0d1cSeric char *
763320e0d1cSeric getrealhostname(fd)
764320e0d1cSeric 	int fd;
765320e0d1cSeric {
766320e0d1cSeric 	register struct hostent *hp;
767e4a929e2Seric 	SOCKADDR sa;
768e2f2f828Seric 	int salen;
769320e0d1cSeric 	char hbuf[MAXNAME];
770320e0d1cSeric 	extern struct hostent *gethostbyaddr();
771320e0d1cSeric 
772e2f2f828Seric 	salen = sizeof sa;
77325f5a145Seric 	if (getsockname(fd, &sa.sa, &salen) < 0 || salen <= 0)
774320e0d1cSeric 		return NULL;
77525f5a145Seric 	hp = gethostbyaddr(sa.sa.sa_data, salen, sa.sa.sa_family);
776320e0d1cSeric 	if (hp != NULL)
777320e0d1cSeric 		(void) strcpy(hbuf, hp->h_name);
778320e0d1cSeric 	else
779e2f2f828Seric 		(void) sprintf(hbuf, "[%s]", anynet_ntoa(&sa));
780320e0d1cSeric 	return hbuf;
781320e0d1cSeric }
782320e0d1cSeric /*
78315d084d5Seric **  MAPHOSTNAME -- turn a hostname into canonical form
78415d084d5Seric **
78515d084d5Seric **	Parameters:
78605b57da8Seric **		map -- a pointer to this map (unused).
78715d084d5Seric **		hbuf -- a buffer containing a hostname.
78815d084d5Seric **		hbsize -- the size of hbuf.
789d798a1deSeric **		avp -- unused -- for compatibility with other mapping
790d798a1deSeric **			functions.
79115d084d5Seric **
79215d084d5Seric **	Returns:
79315d084d5Seric **		The mapping, if found.
79415d084d5Seric **		NULL if no mapping found.
79515d084d5Seric **
79615d084d5Seric **	Side Effects:
79715d084d5Seric **		Looks up the host specified in hbuf.  If it is not
79815d084d5Seric **		the canonical name for that host, return the canonical
79915d084d5Seric **		name.
800f36ede03Sbostic */
801cb452edcSeric 
80215d084d5Seric char *
80305b57da8Seric maphostname(map, hbuf, hbsize, avp)
80405b57da8Seric 	MAP *map;
80599f7cf32Seric 	char *hbuf;
80699f7cf32Seric 	int hbsize;
80715d084d5Seric 	char **avp;
80899f7cf32Seric {
80999f7cf32Seric 	register struct hostent *hp;
8105f78836eSmiriam 	u_long in_addr;
81105b57da8Seric 	char *cp;
81238ad259dSeric 	int i;
813f36ede03Sbostic 	struct hostent *gethostbyaddr();
8145f78836eSmiriam 
81599b358daSeric 	/* allow room for null */
81615d084d5Seric 	hbsize--;
81715d084d5Seric 
818f36ede03Sbostic 	/*
819f36ede03Sbostic 	 * If first character is a bracket, then it is an address
820f36ede03Sbostic 	 * lookup.  Address is copied into a temporary buffer to
821f36ede03Sbostic 	 * strip the brackets and to preserve hbuf if address is
822f36ede03Sbostic 	 * unknown.
823f36ede03Sbostic 	 */
82415d084d5Seric 
825cb452edcSeric 	if (*hbuf != '[')
82615d084d5Seric 	{
827d798a1deSeric 		extern bool getcanonname();
828d798a1deSeric 
8298cb4653dSeric 		if (tTd(9, 1))
8309040ec4fSeric 			printf("maphostname(%s, %d) => ", hbuf, hbsize);
831d5c60ac0Seric 		if (getcanonname(hbuf, hbsize))
8329040ec4fSeric 		{
8339040ec4fSeric 			if (tTd(9, 1))
8349040ec4fSeric 				printf("%s\n", hbuf);
83515d084d5Seric 			return hbuf;
8369040ec4fSeric 		}
83715d084d5Seric 		else
8389040ec4fSeric 		{
8399040ec4fSeric 			if (tTd(9, 1))
8409040ec4fSeric 				printf("FAIL\n");
84115d084d5Seric 			return NULL;
84215d084d5Seric 		}
8439040ec4fSeric 	}
84405b57da8Seric 	if ((cp = strchr(hbuf, ']')) == NULL)
84515d084d5Seric 		return (NULL);
84634e39927Sbostic 	*cp = '\0';
84705b57da8Seric 	in_addr = inet_addr(&hbuf[1]);
84838ad259dSeric 
84938ad259dSeric 	/* check to see if this is one of our addresses */
85038ad259dSeric 	for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
85138ad259dSeric 	{
85238ad259dSeric 		if (MyIpAddrs[i].s_addr == in_addr)
85338ad259dSeric 		{
85438ad259dSeric 			strncpy(hbuf, MyHostName, hbsize);
85538ad259dSeric 			hbuf[hbsize] = '\0';
85638ad259dSeric 			return hbuf;
85738ad259dSeric 		}
85838ad259dSeric 	}
85938ad259dSeric 
86038ad259dSeric 	/* nope -- ask the name server */
86131601fa7Seric 	hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
8625f78836eSmiriam 	if (hp == NULL)
86315d084d5Seric 		return (NULL);
86415d084d5Seric 
86538ad259dSeric 	/* found a match -- copy out */
86605b57da8Seric 	if (strlen(hp->h_name) > hbsize)
86705b57da8Seric 		hp->h_name[hbsize] = '\0';
868fefbbe29Seric 	(void) strcpy(hbuf, hp->h_name);
86915d084d5Seric 	return hbuf;
87099f7cf32Seric }
871e2f2f828Seric /*
872e2f2f828Seric **  ANYNET_NTOA -- convert a network address to printable form.
873e2f2f828Seric **
874e2f2f828Seric **	Parameters:
875e2f2f828Seric **		sap -- a pointer to a sockaddr structure.
876e2f2f828Seric **
877e2f2f828Seric **	Returns:
878e2f2f828Seric **		A printable version of that sockaddr.
879e2f2f828Seric */
880e2f2f828Seric 
881e2f2f828Seric char *
882e2f2f828Seric anynet_ntoa(sap)
883e2f2f828Seric 	register SOCKADDR *sap;
884e2f2f828Seric {
885e2f2f828Seric 	register char *bp;
886e2f2f828Seric 	register char *ap;
887e2f2f828Seric 	int l;
888e2f2f828Seric 	static char buf[80];
889e2f2f828Seric 
8908cb4653dSeric 	/* check for null/zero family */
8918cb4653dSeric 	if (sap == NULL)
8928cb4653dSeric 		return "NULLADDR";
8938cb4653dSeric 	if (sap->sa.sa_family == 0)
8948cb4653dSeric 		return "0";
8958cb4653dSeric 
89683c1f4bcSeric #ifdef NETINET
89783c1f4bcSeric 	if (sap->sa.sa_family == AF_INET)
898e2f2f828Seric 	{
899e2f2f828Seric 		extern char *inet_ntoa();
900e2f2f828Seric 
901e2f2f828Seric 		return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
902e2f2f828Seric 	}
90383c1f4bcSeric #endif
904e2f2f828Seric 
905e2f2f828Seric 	/* unknown family -- just dump bytes */
90683c1f4bcSeric 	(void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
907e2f2f828Seric 	bp = &buf[strlen(buf)];
90883c1f4bcSeric 	ap = sap->sa.sa_data;
90983c1f4bcSeric 	for (l = sizeof sap->sa.sa_data; --l >= 0; )
910e2f2f828Seric 	{
911e2f2f828Seric 		(void) sprintf(bp, "%02x:", *ap++ & 0377);
912e2f2f828Seric 		bp += 3;
913e2f2f828Seric 	}
914e2f2f828Seric 	*--bp = '\0';
915e2f2f828Seric 	return buf;
916e2f2f828Seric }
917f36ede03Sbostic 
9186c2c3107Seric # else /* DAEMON */
91999f7cf32Seric /* code for systems without sophisticated networking */
920444eaf03Seric 
921444eaf03Seric /*
922444eaf03Seric **  MYHOSTNAME -- stub version for case of no daemon code.
92321e9914dSeric **
92421e9914dSeric **	Can't convert to upper case here because might be a UUCP name.
925897f1869Seric **
926897f1869Seric **	Mark, you can change this to be anything you want......
927444eaf03Seric */
928444eaf03Seric 
929444eaf03Seric char **
930897f1869Seric myhostname(hostbuf, size)
931444eaf03Seric 	char hostbuf[];
932897f1869Seric 	int size;
933444eaf03Seric {
934444eaf03Seric 	register FILE *f;
935444eaf03Seric 
936444eaf03Seric 	hostbuf[0] = '\0';
937444eaf03Seric 	f = fopen("/usr/include/whoami", "r");
938444eaf03Seric 	if (f != NULL)
939444eaf03Seric 	{
940897f1869Seric 		(void) fgets(hostbuf, size, f);
941444eaf03Seric 		fixcrlf(hostbuf, TRUE);
942444eaf03Seric 		(void) fclose(f);
943444eaf03Seric 	}
944444eaf03Seric 	return (NULL);
945444eaf03Seric }
94699f7cf32Seric /*
947320e0d1cSeric **  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
948320e0d1cSeric **
949320e0d1cSeric **	Parameters:
950320e0d1cSeric **		fd -- the descriptor
951320e0d1cSeric **
952320e0d1cSeric **	Returns:
953320e0d1cSeric **		The host name associated with this descriptor, if it can
954320e0d1cSeric **			be determined.
955320e0d1cSeric **		NULL otherwise.
956320e0d1cSeric **
957320e0d1cSeric **	Side Effects:
958320e0d1cSeric **		none
959320e0d1cSeric */
960320e0d1cSeric 
961320e0d1cSeric char *
962320e0d1cSeric getrealhostname(fd)
963320e0d1cSeric 	int fd;
964320e0d1cSeric {
965320e0d1cSeric 	return NULL;
966320e0d1cSeric }
967320e0d1cSeric /*
96899f7cf32Seric **  MAPHOSTNAME -- turn a hostname into canonical form
96999f7cf32Seric **
97099f7cf32Seric **	Parameters:
97105b57da8Seric **		map -- a pointer to the database map.
97299f7cf32Seric **		hbuf -- a buffer containing a hostname.
97315d084d5Seric **		avp -- a pointer to a (cf file defined) argument vector.
97499f7cf32Seric **
97599f7cf32Seric **	Returns:
97615d084d5Seric **		mapped host name
977cb452edcSeric **		FALSE otherwise.
97899f7cf32Seric **
97999f7cf32Seric **	Side Effects:
98099f7cf32Seric **		Looks up the host specified in hbuf.  If it is not
98199f7cf32Seric **		the canonical name for that host, replace it with
98299f7cf32Seric **		the canonical name.  If the name is unknown, or it
98399f7cf32Seric **		is already the canonical name, leave it unchanged.
98499f7cf32Seric */
98599f7cf32Seric 
98699f7cf32Seric /*ARGSUSED*/
98715d084d5Seric char *
98805b57da8Seric maphostname(map, hbuf, hbsize, avp)
98905b57da8Seric 	MAP *map;
99099f7cf32Seric 	char *hbuf;
99199f7cf32Seric 	int hbsize;
99215d084d5Seric 	char **avp;
99399f7cf32Seric {
99415d084d5Seric 	return NULL;
99599f7cf32Seric }
99699f7cf32Seric 
9976c2c3107Seric #endif /* DAEMON */
998