xref: /csrg-svn/usr.sbin/sendmail/src/daemon.c (revision 63787)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #include <errno.h>
10 #include <signal.h>
11 #include "sendmail.h"
12 
13 #ifndef lint
14 #ifdef DAEMON
15 static char sccsid[] = "@(#)daemon.c	8.2 (Berkeley) 07/13/93 (with daemon mode)";
16 #else
17 static char sccsid[] = "@(#)daemon.c	8.2 (Berkeley) 07/13/93 (without daemon mode)";
18 #endif
19 #endif /* not lint */
20 
21 #ifdef DAEMON
22 
23 # include <netdb.h>
24 # include <sys/wait.h>
25 # include <sys/time.h>
26 
27 #ifdef NAMED_BIND
28 # include <arpa/nameser.h>
29 # include <resolv.h>
30 #endif
31 
32 /*
33 **  DAEMON.C -- routines to use when running as a daemon.
34 **
35 **	This entire file is highly dependent on the 4.2 BSD
36 **	interprocess communication primitives.  No attempt has
37 **	been made to make this file portable to Version 7,
38 **	Version 6, MPX files, etc.  If you should try such a
39 **	thing yourself, I recommend chucking the entire file
40 **	and starting from scratch.  Basic semantics are:
41 **
42 **	getrequests()
43 **		Opens a port and initiates a connection.
44 **		Returns in a child.  Must set InChannel and
45 **		OutChannel appropriately.
46 **	clrdaemon()
47 **		Close any open files associated with getting
48 **		the connection; this is used when running the queue,
49 **		etc., to avoid having extra file descriptors during
50 **		the queue run and to avoid confusing the network
51 **		code (if it cares).
52 **	makeconnection(host, port, outfile, infile, usesecureport)
53 **		Make a connection to the named host on the given
54 **		port.  Set *outfile and *infile to the files
55 **		appropriate for communication.  Returns zero on
56 **		success, else an exit status describing the
57 **		error.
58 **	host_map_lookup(map, hbuf, avp, pstat)
59 **		Convert the entry in hbuf into a canonical form.
60 */
61 /*
62 **  GETREQUESTS -- open mail IPC port and get requests.
63 **
64 **	Parameters:
65 **		none.
66 **
67 **	Returns:
68 **		none.
69 **
70 **	Side Effects:
71 **		Waits until some interesting activity occurs.  When
72 **		it does, a child is created to process it, and the
73 **		parent waits for completion.  Return from this
74 **		routine is always in the child.  The file pointers
75 **		"InChannel" and "OutChannel" should be set to point
76 **		to the communication channel.
77 */
78 
79 int		DaemonSocket	= -1;		/* fd describing socket */
80 SOCKADDR	DaemonAddr;			/* socket for incoming */
81 int		ListenQueueSize = 10;		/* size of listen queue */
82 
83 getrequests()
84 {
85 	int t;
86 	register struct servent *sp;
87 	int on = 1;
88 	bool refusingconnections = TRUE;
89 	FILE *pidf;
90 	extern void reapchild();
91 
92 	/*
93 	**  Set up the address for the mailer.
94 	*/
95 
96 	if (DaemonAddr.sin.sin_family == 0)
97 		DaemonAddr.sin.sin_family = AF_INET;
98 	if (DaemonAddr.sin.sin_addr.s_addr == 0)
99 		DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
100 	if (DaemonAddr.sin.sin_port == 0)
101 	{
102 		sp = getservbyname("smtp", "tcp");
103 		if (sp == NULL)
104 		{
105 			syserr("554 service \"smtp\" unknown");
106 			goto severe;
107 		}
108 #ifdef _SCO_unix_
109 		DaemonAddr.sin.sin_port = htons(sp->s_port);
110 #else
111 		DaemonAddr.sin.sin_port = sp->s_port;
112 #endif
113 	}
114 
115 	/*
116 	**  Try to actually open the connection.
117 	*/
118 
119 	if (tTd(15, 1))
120 		printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
121 
122 	/* get a socket for the SMTP connection */
123 	DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
124 	if (DaemonSocket < 0)
125 	{
126 		/* probably another daemon already */
127 		syserr("getrequests: can't create socket");
128 	  severe:
129 # ifdef LOG
130 		if (LogLevel > 0)
131 			syslog(LOG_ALERT, "problem creating SMTP socket");
132 # endif /* LOG */
133 		finis();
134 	}
135 
136 	/* turn on network debugging? */
137 	if (tTd(15, 101))
138 		(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
139 
140 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
141 	(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
142 
143 	switch (DaemonAddr.sa.sa_family)
144 	{
145 # ifdef NETINET
146 	  case AF_INET:
147 		t = sizeof DaemonAddr.sin;
148 		break;
149 # endif
150 
151 # ifdef NETISO
152 	  case AF_ISO:
153 		t = sizeof DaemonAddr.siso;
154 		break;
155 # endif
156 
157 	  default:
158 		t = sizeof DaemonAddr;
159 		break;
160 	}
161 
162 	if (bind(DaemonSocket, &DaemonAddr.sa, t) < 0)
163 	{
164 		syserr("getrequests: cannot bind");
165 		(void) close(DaemonSocket);
166 		goto severe;
167 	}
168 
169 	(void) signal(SIGCHLD, reapchild);
170 
171 	/* write the pid to the log file for posterity */
172 	pidf = fopen(PidFile, "w");
173 	if (pidf != NULL)
174 	{
175 		fprintf(pidf, "%d\n", getpid());
176 		fclose(pidf);
177 	}
178 
179 
180 	if (tTd(15, 1))
181 		printf("getrequests: %d\n", DaemonSocket);
182 
183 	for (;;)
184 	{
185 		register int pid;
186 		auto int lotherend;
187 		extern bool refuseconnections();
188 
189 		/* see if we are rejecting connections */
190 		CurrentLA = getla();
191 		if (refuseconnections())
192 		{
193 			if (!refusingconnections)
194 			{
195 				/* don't queue so peer will fail quickly */
196 				(void) listen(DaemonSocket, 0);
197 				refusingconnections = TRUE;
198 			}
199 			setproctitle("rejecting connections: load average: %d",
200 				CurrentLA);
201 			sleep(5);
202 			continue;
203 		}
204 
205 		if (refusingconnections)
206 		{
207 			/* start listening again */
208 			if (listen(DaemonSocket, ListenQueueSize) < 0)
209 			{
210 				syserr("getrequests: cannot listen");
211 				(void) close(DaemonSocket);
212 				goto severe;
213 			}
214 			setproctitle("accepting connections");
215 			refusingconnections = FALSE;
216 		}
217 
218 		/* wait for a connection */
219 		do
220 		{
221 			errno = 0;
222 			lotherend = sizeof RealHostAddr;
223 			t = accept(DaemonSocket,
224 			    (struct sockaddr *)&RealHostAddr, &lotherend);
225 		} while (t < 0 && errno == EINTR);
226 		if (t < 0)
227 		{
228 			syserr("getrequests: accept");
229 			sleep(5);
230 			continue;
231 		}
232 
233 		/*
234 		**  Create a subprocess to process the mail.
235 		*/
236 
237 		if (tTd(15, 2))
238 			printf("getrequests: forking (fd = %d)\n", t);
239 
240 		pid = fork();
241 		if (pid < 0)
242 		{
243 			syserr("daemon: cannot fork");
244 			sleep(10);
245 			(void) close(t);
246 			continue;
247 		}
248 
249 		if (pid == 0)
250 		{
251 			extern char *hostnamebyanyaddr();
252 
253 			/*
254 			**  CHILD -- return to caller.
255 			**	Collect verified idea of sending host.
256 			**	Verify calling user id if possible here.
257 			*/
258 
259 			(void) signal(SIGCHLD, SIG_DFL);
260 			OpMode = MD_SMTP;
261 
262 			/* determine host name */
263 			RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
264 
265 #ifdef LOG
266 			if (LogLevel > 10)
267 			{
268 				/* log connection information */
269 				syslog(LOG_INFO, "connect from %s (%s)",
270 					RealHostName, anynet_ntoa(&RealHostAddr));
271 			}
272 #endif
273 
274 			(void) close(DaemonSocket);
275 			InChannel = fdopen(t, "r");
276 			OutChannel = fdopen(dup(t), "w");
277 
278 			/* should we check for illegal connection here? XXX */
279 #ifdef XLA
280 			if (!xla_host_ok(RealHostName))
281 			{
282 				message("421 Too many SMTP sessions for this host");
283 				exit(0);
284 			}
285 #endif
286 
287 			if (tTd(15, 2))
288 				printf("getreq: returning\n");
289 			return;
290 		}
291 
292 		/* close the port so that others will hang (for a while) */
293 		(void) close(t);
294 	}
295 	/*NOTREACHED*/
296 }
297 /*
298 **  CLRDAEMON -- reset the daemon connection
299 **
300 **	Parameters:
301 **		none.
302 **
303 **	Returns:
304 **		none.
305 **
306 **	Side Effects:
307 **		releases any resources used by the passive daemon.
308 */
309 
310 clrdaemon()
311 {
312 	if (DaemonSocket >= 0)
313 		(void) close(DaemonSocket);
314 	DaemonSocket = -1;
315 }
316 /*
317 **  SETDAEMONOPTIONS -- set options for running the daemon
318 **
319 **	Parameters:
320 **		p -- the options line.
321 **
322 **	Returns:
323 **		none.
324 */
325 
326 setdaemonoptions(p)
327 	register char *p;
328 {
329 	if (DaemonAddr.sa.sa_family == AF_UNSPEC)
330 		DaemonAddr.sa.sa_family = AF_INET;
331 
332 	while (p != NULL)
333 	{
334 		register char *f;
335 		register char *v;
336 
337 		while (isascii(*p) && isspace(*p))
338 			p++;
339 		if (*p == '\0')
340 			break;
341 		f = p;
342 		p = strchr(p, ',');
343 		if (p != NULL)
344 			*p++ = '\0';
345 		v = strchr(f, '=');
346 		if (v == NULL)
347 			continue;
348 		while (isascii(*++v) && isspace(*v))
349 			continue;
350 
351 		switch (*f)
352 		{
353 		  case 'F':		/* address family */
354 			if (isascii(*v) && isdigit(*v))
355 				DaemonAddr.sa.sa_family = atoi(v);
356 #ifdef NETINET
357 			else if (strcasecmp(v, "inet") == 0)
358 				DaemonAddr.sa.sa_family = AF_INET;
359 #endif
360 #ifdef NETISO
361 			else if (strcasecmp(v, "iso") == 0)
362 				DaemonAddr.sa.sa_family = AF_ISO;
363 #endif
364 #ifdef NETNS
365 			else if (strcasecmp(v, "ns") == 0)
366 				DaemonAddr.sa.sa_family = AF_NS;
367 #endif
368 #ifdef NETX25
369 			else if (strcasecmp(v, "x.25") == 0)
370 				DaemonAddr.sa.sa_family = AF_CCITT;
371 #endif
372 			else
373 				syserr("554 Unknown address family %s in Family=option", v);
374 			break;
375 
376 		  case 'A':		/* address */
377 			switch (DaemonAddr.sa.sa_family)
378 			{
379 #ifdef NETINET
380 			  case AF_INET:
381 				if (isascii(*v) && isdigit(*v))
382 					DaemonAddr.sin.sin_addr.s_addr = inet_network(v);
383 				else
384 				{
385 					register struct netent *np;
386 
387 					np = getnetbyname(v);
388 					if (np == NULL)
389 						syserr("554 network \"%s\" unknown", v);
390 					else
391 						DaemonAddr.sin.sin_addr.s_addr = np->n_net;
392 				}
393 				break;
394 #endif
395 
396 			  default:
397 				syserr("554 Address= option unsupported for family %d",
398 					DaemonAddr.sa.sa_family);
399 				break;
400 			}
401 			break;
402 
403 		  case 'P':		/* port */
404 			switch (DaemonAddr.sa.sa_family)
405 			{
406 				short port;
407 
408 #ifdef NETINET
409 			  case AF_INET:
410 				if (isascii(*v) && isdigit(*v))
411 					DaemonAddr.sin.sin_port = atoi(v);
412 				else
413 				{
414 					register struct servent *sp;
415 
416 					sp = getservbyname(v, "tcp");
417 					if (sp == NULL)
418 						syserr("554 service \"%s\" unknown", v);
419 					else
420 					{
421 #ifdef _SCO_unix_
422 						DaemonAddr.sin.sin_port = htons(sp->s_port);
423 #else
424 						DaemonAddr.sin.sin_port = sp->s_port;
425 #endif
426 					}
427 				}
428 				break;
429 #endif
430 
431 #ifdef NETISO
432 			  case AF_ISO:
433 				/* assume two byte transport selector */
434 				if (isascii(*v) && isdigit(*v))
435 					port = atoi(v);
436 				else
437 				{
438 					register struct servent *sp;
439 
440 					sp = getservbyname(v, "tcp");
441 					if (sp == NULL)
442 						syserr("554 service \"%s\" unknown", v);
443 					else
444 						port = sp->s_port;
445 				}
446 				bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
447 				break;
448 #endif
449 
450 			  default:
451 				syserr("554 Port= option unsupported for family %d",
452 					DaemonAddr.sa.sa_family);
453 				break;
454 			}
455 			break;
456 
457 		  case 'L':		/* listen queue size */
458 			ListenQueueSize = atoi(v);
459 			break;
460 		}
461 	}
462 }
463 /*
464 **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
465 **
466 **	Parameters:
467 **		host -- the name of the host.
468 **		port -- the port number to connect to.
469 **		mci -- a pointer to the mail connection information
470 **			structure to be filled in.
471 **		usesecureport -- if set, use a low numbered (reserved)
472 **			port to provide some rudimentary authentication.
473 **
474 **	Returns:
475 **		An exit code telling whether the connection could be
476 **			made and if not why not.
477 **
478 **	Side Effects:
479 **		none.
480 */
481 
482 SOCKADDR	CurHostAddr;		/* address of current host */
483 
484 int
485 makeconnection(host, port, mci, usesecureport)
486 	char *host;
487 	u_short port;
488 	register MCI *mci;
489 	bool usesecureport;
490 {
491 	register int i, s;
492 	register struct hostent *hp = (struct hostent *)NULL;
493 	SOCKADDR addr;
494 	int sav_errno;
495 	int addrlen;
496 #ifdef NAMED_BIND
497 	extern int h_errno;
498 #endif
499 
500 	/*
501 	**  Set up the address for the mailer.
502 	**	Accept "[a.b.c.d]" syntax for host name.
503 	*/
504 
505 #ifdef NAMED_BIND
506 	h_errno = 0;
507 #endif
508 	errno = 0;
509 	bzero(&CurHostAddr, sizeof CurHostAddr);
510 	CurHostName = host;
511 
512 	if (host[0] == '[')
513 	{
514 		long hid;
515 		register char *p = strchr(host, ']');
516 
517 		if (p != NULL)
518 		{
519 			*p = '\0';
520 #ifdef NETINET
521 			hid = inet_addr(&host[1]);
522 			if (hid == -1)
523 #endif
524 			{
525 				/* try it as a host name (avoid MX lookup) */
526 				hp = gethostbyname(&host[1]);
527 				*p = ']';
528 				goto gothostent;
529 			}
530 			*p = ']';
531 		}
532 		if (p == NULL)
533 		{
534 			usrerr("553 Invalid numeric domain spec \"%s\"", host);
535 			return (EX_NOHOST);
536 		}
537 #ifdef NETINET
538 		addr.sin.sin_family = AF_INET;		/*XXX*/
539 		addr.sin.sin_addr.s_addr = hid;
540 #endif
541 	}
542 	else
543 	{
544 		hp = gethostbyname(host);
545 gothostent:
546 		if (hp == NULL)
547 		{
548 #ifdef NAMED_BIND
549 			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
550 				return (EX_TEMPFAIL);
551 
552 			/* if name server is specified, assume temp fail */
553 			if (errno == ECONNREFUSED && UseNameServer)
554 				return (EX_TEMPFAIL);
555 #endif
556 			return (EX_NOHOST);
557 		}
558 		addr.sa.sa_family = hp->h_addrtype;
559 		switch (hp->h_addrtype)
560 		{
561 #ifdef NETINET
562 		  case AF_INET:
563 			bcopy(hp->h_addr,
564 				&addr.sin.sin_addr,
565 				hp->h_length);
566 			break;
567 #endif
568 
569 		  default:
570 			bcopy(hp->h_addr,
571 				addr.sa.sa_data,
572 				hp->h_length);
573 			break;
574 		}
575 		i = 1;
576 	}
577 
578 	/*
579 	**  Determine the port number.
580 	*/
581 
582 	if (port != 0)
583 		port = htons(port);
584 	else
585 	{
586 		register struct servent *sp = getservbyname("smtp", "tcp");
587 
588 		if (sp == NULL)
589 		{
590 			syserr("554 makeconnection: service \"smtp\" unknown");
591 			return (EX_OSERR);
592 		}
593 #ifdef _SCO_unix_
594 		port = htons(sp->s_port);
595 #else
596 		port = sp->s_port;
597 #endif
598 	}
599 
600 	switch (addr.sa.sa_family)
601 	{
602 #ifdef NETINET
603 	  case AF_INET:
604 		addr.sin.sin_port = port;
605 		addrlen = sizeof (struct sockaddr_in);
606 		break;
607 #endif
608 
609 #ifdef NETISO
610 	  case AF_ISO:
611 		/* assume two byte transport selector */
612 		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
613 		addrlen = sizeof (struct sockaddr_iso);
614 		break;
615 #endif
616 
617 	  default:
618 		syserr("Can't connect to address family %d", addr.sa.sa_family);
619 		return (EX_NOHOST);
620 	}
621 
622 	/*
623 	**  Try to actually open the connection.
624 	*/
625 
626 #ifdef XLA
627 	/* if too many connections, don't bother trying */
628 	if (!xla_noqueue_ok(host))
629 		return EX_TEMPFAIL;
630 #endif
631 
632 	for (;;)
633 	{
634 		if (tTd(16, 1))
635 			printf("makeconnection (%s [%s])\n",
636 				host, anynet_ntoa(&addr));
637 
638 		/* save for logging */
639 		CurHostAddr = addr;
640 
641 		if (usesecureport)
642 		{
643 			int rport = IPPORT_RESERVED - 1;
644 
645 			s = rresvport(&rport);
646 		}
647 		else
648 		{
649 			s = socket(AF_INET, SOCK_STREAM, 0);
650 		}
651 		if (s < 0)
652 		{
653 			sav_errno = errno;
654 			syserr("makeconnection: no socket");
655 			goto failure;
656 		}
657 
658 		if (tTd(16, 1))
659 			printf("makeconnection: fd=%d\n", s);
660 
661 		/* turn on network debugging? */
662 		if (tTd(16, 101))
663 		{
664 			int on = 1;
665 			(void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
666 					  (char *)&on, sizeof on);
667 		}
668 		if (CurEnv->e_xfp != NULL)
669 			(void) fflush(CurEnv->e_xfp);		/* for debugging */
670 		errno = 0;					/* for debugging */
671 		if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
672 			break;
673 
674 		/* couldn't connect.... figure out why */
675 		sav_errno = errno;
676 		(void) close(s);
677 		if (hp && hp->h_addr_list[i])
678 		{
679 			if (tTd(16, 1))
680 				printf("Connect failed (%s); trying new address....\n",
681 					errstring(sav_errno));
682 			switch (addr.sa.sa_family)
683 			{
684 #ifdef NETINET
685 			  case AF_INET:
686 				bcopy(hp->h_addr_list[i++],
687 				      &addr.sin.sin_addr,
688 				      hp->h_length);
689 				break;
690 #endif
691 
692 			  default:
693 				bcopy(hp->h_addr_list[i++],
694 					addr.sa.sa_data,
695 					hp->h_length);
696 				break;
697 			}
698 			continue;
699 		}
700 
701 		/* failure, decide if temporary or not */
702 	failure:
703 #ifdef XLA
704 		xla_host_end(host);
705 #endif
706 		if (transienterror(sav_errno))
707 			return EX_TEMPFAIL;
708 		else
709 		{
710 			message("%s", errstring(sav_errno));
711 			return (EX_UNAVAILABLE);
712 		}
713 	}
714 
715 	/* connection ok, put it into canonical form */
716 	mci->mci_out = fdopen(s, "w");
717 	mci->mci_in = fdopen(dup(s), "r");
718 
719 	return (EX_OK);
720 }
721 /*
722 **  MYHOSTNAME -- return the name of this host.
723 **
724 **	Parameters:
725 **		hostbuf -- a place to return the name of this host.
726 **		size -- the size of hostbuf.
727 **
728 **	Returns:
729 **		A list of aliases for this host.
730 **
731 **	Side Effects:
732 **		Sets the MyIpAddrs buffer to a list of my IP addresses.
733 */
734 
735 struct in_addr	MyIpAddrs[MAXIPADDR + 1];
736 
737 char **
738 myhostname(hostbuf, size)
739 	char hostbuf[];
740 	int size;
741 {
742 	register struct hostent *hp;
743 	extern struct hostent *gethostbyname();
744 
745 	if (gethostname(hostbuf, size) < 0)
746 	{
747 		(void) strcpy(hostbuf, "localhost");
748 	}
749 	hp = gethostbyname(hostbuf);
750 	if (hp != NULL)
751 	{
752 		(void) strncpy(hostbuf, hp->h_name, size - 1);
753 		hostbuf[size - 1] = '\0';
754 
755 		if (hp->h_addrtype == AF_INET && hp->h_length == 4)
756 		{
757 			register int i;
758 
759 			for (i = 0; i < MAXIPADDR; i++)
760 			{
761 				if (hp->h_addr_list[i] == NULL)
762 					break;
763 				MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
764 			}
765 			MyIpAddrs[i].s_addr = 0;
766 		}
767 
768 		return (hp->h_aliases);
769 	}
770 	else
771 		return (NULL);
772 }
773 /*
774 **  GETAUTHINFO -- get the real host name asociated with a file descriptor
775 **
776 **	Uses RFC1413 protocol to try to get info from the other end.
777 **
778 **	Parameters:
779 **		fd -- the descriptor
780 **
781 **	Returns:
782 **		The user@host information associated with this descriptor.
783 **
784 **	Side Effects:
785 **		Sets RealHostName to the name of the host at the other end.
786 */
787 
788 #ifdef IDENTPROTO
789 
790 static jmp_buf	CtxAuthTimeout;
791 
792 static
793 authtimeout()
794 {
795 	longjmp(CtxAuthTimeout, 1);
796 }
797 
798 #endif
799 
800 char *
801 getauthinfo(fd)
802 	int fd;
803 {
804 	SOCKADDR fa;
805 	int falen;
806 	register char *p;
807 #ifdef IDENTPROTO
808 	SOCKADDR la;
809 	int lalen;
810 	register struct servent *sp;
811 	int s;
812 	int i;
813 	EVENT *ev;
814 #endif
815 	static char hbuf[MAXNAME * 2 + 2];
816 	extern char *hostnamebyanyaddr();
817 	extern char RealUserName[];			/* main.c */
818 
819 	falen = sizeof fa;
820 	if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0)
821 	{
822 		RealHostName = "localhost";
823 		(void) sprintf(hbuf, "%s@localhost", RealUserName);
824 		if (tTd(9, 1))
825 			printf("getauthinfo: %s\n", hbuf);
826 		return hbuf;
827 	}
828 
829 	RealHostName = newstr(hostnamebyanyaddr(&fa));
830 	RealHostAddr = fa;
831 
832 #ifdef IDENTPROTO
833 	lalen = sizeof la;
834 	if (fa.sa.sa_family != AF_INET ||
835 	    getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
836 	    la.sa.sa_family != AF_INET)
837 	{
838 		/* no ident info */
839 		goto noident;
840 	}
841 
842 	/* create ident query */
843 	(void) sprintf(hbuf, "%d,%d\r\n",
844 		ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port));
845 
846 	/* create local address */
847 	bzero(&la, sizeof la);
848 
849 	/* create foreign address */
850 	sp = getservbyname("auth", "tcp");
851 	if (sp != NULL)
852 	{
853 #ifdef _SCO_unix_
854 		fa.sin.sin_port = htons(sp->s_port);
855 #else
856 		fa.sin.sin_port = sp->s_port;
857 #endif
858 	}
859 	else
860 		fa.sin.sin_port = htons(113);
861 
862 	s = -1;
863 	if (setjmp(CtxAuthTimeout) != 0)
864 	{
865 		if (s >= 0)
866 			(void) close(s);
867 		goto noident;
868 	}
869 
870 	/* put a timeout around the whole thing */
871 	ev = setevent((time_t) 30, authtimeout, 0);
872 
873 	/* connect to foreign IDENT server */
874 	s = socket(AF_INET, SOCK_STREAM, 0);
875 	if (s < 0)
876 	{
877 		clrevent(ev);
878 		goto noident;
879 	}
880 	if (connect(s, &fa.sa, sizeof fa.sin) < 0)
881 	{
882 closeident:
883 		(void) close(s);
884 		clrevent(ev);
885 		goto noident;
886 	}
887 
888 	if (tTd(9, 10))
889 		printf("getauthinfo: sent %s", hbuf);
890 
891 	/* send query */
892 	if (write(s, hbuf, strlen(hbuf)) < 0)
893 		goto closeident;
894 
895 	/* get result */
896 	i = read(s, hbuf, sizeof hbuf);
897 	(void) close(s);
898 	clrevent(ev);
899 	if (i <= 0)
900 		goto noident;
901 	if (hbuf[--i] == '\n' && hbuf[--i] == '\r')
902 		i--;
903 	hbuf[++i] = '\0';
904 
905 	if (tTd(9, 3))
906 		printf("getauthinfo:  got %s\n", hbuf);
907 
908 	/* parse result */
909 	p = strchr(hbuf, ':');
910 	if (p == NULL)
911 	{
912 		/* malformed response */
913 		goto noident;
914 	}
915 	while (isascii(*++p) && isspace(*p))
916 		continue;
917 	if (strncasecmp(p, "userid", 6) != 0)
918 	{
919 		/* presumably an error string */
920 		goto noident;
921 	}
922 	p += 6;
923 	while (isascii(*p) && isspace(*p))
924 		p++;
925 	if (*p++ != ':')
926 	{
927 		/* either useridxx or malformed response */
928 		goto noident;
929 	}
930 
931 	/* p now points to the OSTYPE field */
932 	p = strchr(p, ':');
933 	if (p == NULL)
934 	{
935 		/* malformed response */
936 		goto noident;
937 	}
938 
939 	/* 1413 says don't do this -- but it's broken otherwise */
940 	while (isascii(*++p) && isspace(*p))
941 		continue;
942 
943 	/* p now points to the authenticated name */
944 	(void) sprintf(hbuf, "%s@%s", p, RealHostName);
945 	goto finish;
946 
947 #endif /* IDENTPROTO */
948 
949 noident:
950 	(void) strcpy(hbuf, RealHostName);
951 
952 finish:
953 	if (RealHostName[0] != '[')
954 	{
955 		p = &hbuf[strlen(hbuf)];
956 		(void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
957 	}
958 	if (tTd(9, 1))
959 		printf("getauthinfo: %s\n", hbuf);
960 	return hbuf;
961 }
962 /*
963 **  HOST_MAP_LOOKUP -- turn a hostname into canonical form
964 **
965 **	Parameters:
966 **		map -- a pointer to this map (unused).
967 **		name -- the (presumably unqualified) hostname.
968 **		av -- unused -- for compatibility with other mapping
969 **			functions.
970 **		statp -- an exit status (out parameter) -- set to
971 **			EX_TEMPFAIL if the name server is unavailable.
972 **
973 **	Returns:
974 **		The mapping, if found.
975 **		NULL if no mapping found.
976 **
977 **	Side Effects:
978 **		Looks up the host specified in hbuf.  If it is not
979 **		the canonical name for that host, return the canonical
980 **		name.
981 */
982 
983 char *
984 host_map_lookup(map, name, av, statp)
985 	MAP *map;
986 	char *name;
987 	char **av;
988 	int *statp;
989 {
990 	register struct hostent *hp;
991 	u_long in_addr;
992 	char *cp;
993 	int i;
994 	register STAB *s;
995 	char hbuf[MAXNAME];
996 	extern struct hostent *gethostbyaddr();
997 	extern int h_errno;
998 
999 	/*
1000 	**  See if we have already looked up this name.  If so, just
1001 	**  return it.
1002 	*/
1003 
1004 	s = stab(name, ST_NAMECANON, ST_ENTER);
1005 	if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
1006 	{
1007 		if (tTd(9, 1))
1008 			printf("host_map_lookup(%s) => CACHE %s\n",
1009 				name, s->s_namecanon.nc_cname);
1010 		errno = s->s_namecanon.nc_errno;
1011 		h_errno = s->s_namecanon.nc_herrno;
1012 		*statp = s->s_namecanon.nc_stat;
1013 		return s->s_namecanon.nc_cname;
1014 	}
1015 
1016 	/*
1017 	**  If first character is a bracket, then it is an address
1018 	**  lookup.  Address is copied into a temporary buffer to
1019 	**  strip the brackets and to preserve name if address is
1020 	**  unknown.
1021 	*/
1022 
1023 	if (*name != '[')
1024 	{
1025 		extern bool getcanonname();
1026 
1027 		if (tTd(9, 1))
1028 			printf("host_map_lookup(%s) => ", name);
1029 		s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
1030 		(void) strcpy(hbuf, name);
1031 		if (getcanonname(hbuf, sizeof hbuf - 1))
1032 		{
1033 			if (tTd(9, 1))
1034 				printf("%s\n", hbuf);
1035 			cp = map_rewrite(map, hbuf, strlen(hbuf), av);
1036 			s->s_namecanon.nc_cname = newstr(cp);
1037 			return cp;
1038 		}
1039 		else
1040 		{
1041 			register struct hostent *hp;
1042 
1043 			if (tTd(9, 1))
1044 				printf("FAIL (%d)\n", h_errno);
1045 			s->s_namecanon.nc_errno = errno;
1046 			s->s_namecanon.nc_herrno = h_errno;
1047 			switch (h_errno)
1048 			{
1049 			  case TRY_AGAIN:
1050 				if (UseNameServer)
1051 				{
1052 					char *msg = "Recipient domain nameserver timed out";
1053 
1054 					message(msg);
1055 					if (CurEnv->e_message == NULL)
1056 						CurEnv->e_message = newstr(msg);
1057 				}
1058 				*statp = EX_TEMPFAIL;
1059 				break;
1060 
1061 			  case HOST_NOT_FOUND:
1062 				*statp = EX_NOHOST;
1063 				break;
1064 
1065 			  case NO_RECOVERY:
1066 				*statp = EX_SOFTWARE;
1067 				break;
1068 
1069 			  default:
1070 				*statp = EX_UNAVAILABLE;
1071 				break;
1072 			}
1073 			s->s_namecanon.nc_stat = *statp;
1074 			if (*statp != EX_TEMPFAIL || UseNameServer)
1075 				return NULL;
1076 
1077 			/*
1078 			**  Try to look it up in /etc/hosts
1079 			*/
1080 
1081 			hp = gethostbyname(name);
1082 			if (hp == NULL)
1083 			{
1084 				/* no dice there either */
1085 				s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1086 				return NULL;
1087 			}
1088 
1089 			s->s_namecanon.nc_stat = *statp = EX_OK;
1090 			cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1091 			s->s_namecanon.nc_cname = newstr(cp);
1092 			return cp;
1093 		}
1094 	}
1095 	if ((cp = strchr(name, ']')) == NULL)
1096 		return (NULL);
1097 	*cp = '\0';
1098 	in_addr = inet_addr(&name[1]);
1099 
1100 	/* check to see if this is one of our addresses */
1101 	for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
1102 	{
1103 		if (MyIpAddrs[i].s_addr == in_addr)
1104 		{
1105 			return map_rewrite(map, MyHostName, strlen(MyHostName), av);
1106 		}
1107 	}
1108 
1109 	/* nope -- ask the name server */
1110 	hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
1111 	s->s_namecanon.nc_errno = errno;
1112 	s->s_namecanon.nc_herrno = h_errno;
1113 	s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
1114 	if (hp == NULL)
1115 	{
1116 		s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1117 		return (NULL);
1118 	}
1119 
1120 	/* found a match -- copy out */
1121 	cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1122 	s->s_namecanon.nc_stat = *statp = EX_OK;
1123 	s->s_namecanon.nc_cname = newstr(cp);
1124 	return cp;
1125 }
1126 /*
1127 **  ANYNET_NTOA -- convert a network address to printable form.
1128 **
1129 **	Parameters:
1130 **		sap -- a pointer to a sockaddr structure.
1131 **
1132 **	Returns:
1133 **		A printable version of that sockaddr.
1134 */
1135 
1136 char *
1137 anynet_ntoa(sap)
1138 	register SOCKADDR *sap;
1139 {
1140 	register char *bp;
1141 	register char *ap;
1142 	int l;
1143 	static char buf[80];
1144 
1145 	/* check for null/zero family */
1146 	if (sap == NULL)
1147 		return "NULLADDR";
1148 	if (sap->sa.sa_family == 0)
1149 		return "0";
1150 
1151 #ifdef NETINET
1152 	if (sap->sa.sa_family == AF_INET)
1153 	{
1154 		extern char *inet_ntoa();
1155 
1156 		return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
1157 	}
1158 #endif
1159 
1160 	/* unknown family -- just dump bytes */
1161 	(void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
1162 	bp = &buf[strlen(buf)];
1163 	ap = sap->sa.sa_data;
1164 	for (l = sizeof sap->sa.sa_data; --l >= 0; )
1165 	{
1166 		(void) sprintf(bp, "%02x:", *ap++ & 0377);
1167 		bp += 3;
1168 	}
1169 	*--bp = '\0';
1170 	return buf;
1171 }
1172 /*
1173 **  HOSTNAMEBYANYADDR -- return name of host based on address
1174 **
1175 **	Parameters:
1176 **		sap -- SOCKADDR pointer
1177 **
1178 **	Returns:
1179 **		text representation of host name.
1180 **
1181 **	Side Effects:
1182 **		none.
1183 */
1184 
1185 char *
1186 hostnamebyanyaddr(sap)
1187 	register SOCKADDR *sap;
1188 {
1189 	register struct hostent *hp;
1190 
1191 #ifdef NAMED_BIND
1192 	int saveretry;
1193 
1194 	/* shorten name server timeout to avoid higher level timeouts */
1195 	saveretry = _res.retry;
1196 	_res.retry = 3;
1197 #endif /* NAMED_BIND */
1198 
1199 	switch (sap->sa.sa_family)
1200 	{
1201 #ifdef NETINET
1202 	  case AF_INET:
1203 		hp = gethostbyaddr((char *) &sap->sin.sin_addr,
1204 			sizeof sap->sin.sin_addr,
1205 			AF_INET);
1206 		break;
1207 #endif
1208 
1209 #ifdef NETISO
1210 	  case AF_ISO:
1211 		hp = gethostbyaddr((char *) &sap->siso.siso_addr,
1212 			sizeof sap->siso.siso_addr,
1213 			AF_ISO);
1214 		break;
1215 #endif
1216 
1217 	  default:
1218 		hp = gethostbyaddr(sap->sa.sa_data,
1219 			   sizeof sap->sa.sa_data,
1220 			   sap->sa.sa_family);
1221 		break;
1222 	}
1223 
1224 #ifdef NAMED_BIND
1225 	_res.retry = saveretry;
1226 #endif /* NAMED_BIND */
1227 
1228 	if (hp != NULL)
1229 		return hp->h_name;
1230 	else
1231 	{
1232 		/* produce a dotted quad */
1233 		static char buf[512];
1234 
1235 		(void) sprintf(buf, "[%s]", anynet_ntoa(sap));
1236 		return buf;
1237 	}
1238 }
1239 
1240 # else /* DAEMON */
1241 /* code for systems without sophisticated networking */
1242 
1243 /*
1244 **  MYHOSTNAME -- stub version for case of no daemon code.
1245 **
1246 **	Can't convert to upper case here because might be a UUCP name.
1247 **
1248 **	Mark, you can change this to be anything you want......
1249 */
1250 
1251 char **
1252 myhostname(hostbuf, size)
1253 	char hostbuf[];
1254 	int size;
1255 {
1256 	register FILE *f;
1257 
1258 	hostbuf[0] = '\0';
1259 	f = fopen("/usr/include/whoami", "r");
1260 	if (f != NULL)
1261 	{
1262 		(void) fgets(hostbuf, size, f);
1263 		fixcrlf(hostbuf, TRUE);
1264 		(void) fclose(f);
1265 	}
1266 	return (NULL);
1267 }
1268 /*
1269 **  GETAUTHINFO -- get the real host name asociated with a file descriptor
1270 **
1271 **	Parameters:
1272 **		fd -- the descriptor
1273 **
1274 **	Returns:
1275 **		The host name associated with this descriptor, if it can
1276 **			be determined.
1277 **		NULL otherwise.
1278 **
1279 **	Side Effects:
1280 **		none
1281 */
1282 
1283 char *
1284 getauthinfo(fd)
1285 	int fd;
1286 {
1287 	return NULL;
1288 }
1289 /*
1290 **  MAPHOSTNAME -- turn a hostname into canonical form
1291 **
1292 **	Parameters:
1293 **		map -- a pointer to the database map.
1294 **		name -- a buffer containing a hostname.
1295 **		avp -- a pointer to a (cf file defined) argument vector.
1296 **		statp -- an exit status (out parameter).
1297 **
1298 **	Returns:
1299 **		mapped host name
1300 **		FALSE otherwise.
1301 **
1302 **	Side Effects:
1303 **		Looks up the host specified in name.  If it is not
1304 **		the canonical name for that host, replace it with
1305 **		the canonical name.  If the name is unknown, or it
1306 **		is already the canonical name, leave it unchanged.
1307 */
1308 
1309 /*ARGSUSED*/
1310 char *
1311 host_map_lookup(map, name, avp, statp)
1312 	MAP *map;
1313 	char *name;
1314 	char **avp;
1315 	char *statp;
1316 {
1317 	register struct hostent *hp;
1318 
1319 	hp = gethostbyname(name);
1320 	if (hp != NULL)
1321 		return hp->h_name;
1322 	*statp = EX_NOHOST;
1323 	return NULL;
1324 }
1325 
1326 #endif /* DAEMON */
1327