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