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