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