xref: /freebsd/contrib/sendmail/src/daemon.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
1 /*
2  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * By using this file, you agree to the terms and conditions set
8  * forth in the LICENSE file which can be found at the top level of
9  * the sendmail distribution.
10  *
11  */
12 
13 #include <errno.h>
14 #include "sendmail.h"
15 
16 #ifndef lint
17 #ifdef DAEMON
18 static char sccsid[] = "@(#)daemon.c	8.220 (Berkeley) 6/24/98 (with daemon mode)";
19 #else
20 static char sccsid[] = "@(#)daemon.c	8.220 (Berkeley) 6/24/98 (without daemon mode)";
21 #endif
22 #endif /* not lint */
23 
24 #if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
25 # define USE_SOCK_STREAM	1
26 #endif
27 
28 #if DAEMON || defined(USE_SOCK_STREAM)
29 # include <arpa/inet.h>
30 # if NAMED_BIND
31 #  include <resolv.h>
32 #  ifndef NO_DATA
33 #   define NO_DATA	NO_ADDRESS
34 #  endif
35 # endif
36 #endif
37 
38 #if DAEMON
39 
40 # include <sys/time.h>
41 
42 # if IP_SRCROUTE
43 #  include <netinet/in_systm.h>
44 #  include <netinet/ip.h>
45 #  include <netinet/ip_var.h>
46 # endif
47 
48 /*
49 **  DAEMON.C -- routines to use when running as a daemon.
50 **
51 **	This entire file is highly dependent on the 4.2 BSD
52 **	interprocess communication primitives.  No attempt has
53 **	been made to make this file portable to Version 7,
54 **	Version 6, MPX files, etc.  If you should try such a
55 **	thing yourself, I recommend chucking the entire file
56 **	and starting from scratch.  Basic semantics are:
57 **
58 **	getrequests(e)
59 **		Opens a port and initiates a connection.
60 **		Returns in a child.  Must set InChannel and
61 **		OutChannel appropriately.
62 **	clrdaemon()
63 **		Close any open files associated with getting
64 **		the connection; this is used when running the queue,
65 **		etc., to avoid having extra file descriptors during
66 **		the queue run and to avoid confusing the network
67 **		code (if it cares).
68 **	makeconnection(host, port, outfile, infile, e)
69 **		Make a connection to the named host on the given
70 **		port.  Set *outfile and *infile to the files
71 **		appropriate for communication.  Returns zero on
72 **		success, else an exit status describing the
73 **		error.
74 **	host_map_lookup(map, hbuf, avp, pstat)
75 **		Convert the entry in hbuf into a canonical form.
76 */
77 /*
78 **  GETREQUESTS -- open mail IPC port and get requests.
79 **
80 **	Parameters:
81 **		e -- the current envelope.
82 **
83 **	Returns:
84 **		none.
85 **
86 **	Side Effects:
87 **		Waits until some interesting activity occurs.  When
88 **		it does, a child is created to process it, and the
89 **		parent waits for completion.  Return from this
90 **		routine is always in the child.  The file pointers
91 **		"InChannel" and "OutChannel" should be set to point
92 **		to the communication channel.
93 */
94 
95 int		DaemonSocket	= -1;		/* fd describing socket */
96 SOCKADDR	DaemonAddr;			/* socket for incoming */
97 int		ListenQueueSize = 10;		/* size of listen queue */
98 int		TcpRcvBufferSize = 0;		/* size of TCP receive buffer */
99 int		TcpSndBufferSize = 0;		/* size of TCP send buffer */
100 
101 void
102 getrequests(e)
103 	ENVELOPE *e;
104 {
105 	int t;
106 	bool refusingconnections = TRUE;
107 	FILE *pidf;
108 	int socksize;
109 	u_short port;
110 #if XDEBUG
111 	bool j_has_dot;
112 #endif
113 	extern void reapchild __P((int));
114 	extern int opendaemonsocket __P((bool));
115 
116 	/*
117 	**  Set up the address for the mailer.
118 	*/
119 
120 	switch (DaemonAddr.sa.sa_family)
121 	{
122 	  case AF_UNSPEC:
123 		DaemonAddr.sa.sa_family = AF_INET;
124 		/* fall through ... */
125 
126 	  case AF_INET:
127 		if (DaemonAddr.sin.sin_addr.s_addr == 0)
128 			DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
129 		port = DaemonAddr.sin.sin_port;
130 		break;
131 
132 	  default:
133 		/* unknown protocol */
134 		port = 0;
135 		break;
136 	}
137 	if (port == 0)
138 	{
139 		register struct servent *sp;
140 
141 		sp = getservbyname("smtp", "tcp");
142 		if (sp == NULL)
143 		{
144 			syserr("554 service \"smtp\" unknown");
145 			port = htons(25);
146 		}
147 		else
148 			port = sp->s_port;
149 	}
150 
151 	switch (DaemonAddr.sa.sa_family)
152 	{
153 	  case AF_INET:
154 		DaemonAddr.sin.sin_port = port;
155 		break;
156 
157 	  default:
158 		/* unknown protocol */
159 		break;
160 	}
161 
162 	/*
163 	**  Try to actually open the connection.
164 	*/
165 
166 	if (tTd(15, 1))
167 		printf("getrequests: port 0x%x\n", port);
168 
169 	/* get a socket for the SMTP connection */
170 	socksize = opendaemonsocket(TRUE);
171 
172 	(void) setsignal(SIGCHLD, reapchild);
173 
174 	/* write the pid to the log file for posterity */
175 	pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644,
176 			 SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT);
177 	if (pidf == NULL)
178 	{
179 		sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile);
180 	}
181 	else
182 	{
183 		extern char *CommandLineArgs;
184 
185 		/* write the process id on line 1 */
186 		fprintf(pidf, "%ld\n", (long) getpid());
187 
188 		/* line 2 contains all command line flags */
189 		fprintf(pidf, "%s\n", CommandLineArgs);
190 
191 		/* flush and close */
192 		fclose(pidf);
193 	}
194 
195 #if XDEBUG
196 	{
197 		char jbuf[MAXHOSTNAMELEN];
198 
199 		expand("\201j", jbuf, sizeof jbuf, e);
200 		j_has_dot = strchr(jbuf, '.') != NULL;
201 	}
202 #endif
203 
204 	if (tTd(15, 1))
205 		printf("getrequests: %d\n", DaemonSocket);
206 
207 	for (;;)
208 	{
209 		register pid_t pid;
210 		auto SOCKADDR_LEN_T lotherend;
211 		int savederrno;
212 		int pipefd[2];
213 		extern bool refuseconnections __P((int));
214 
215 		/* see if we are rejecting connections */
216 		(void) blocksignal(SIGALRM);
217 		if (refuseconnections(ntohs(port)))
218 		{
219 			if (DaemonSocket >= 0)
220 			{
221 				/* close socket so peer will fail quickly */
222 				(void) close(DaemonSocket);
223 				DaemonSocket = -1;
224 			}
225 			refusingconnections = TRUE;
226 			sleep(15);
227 			continue;
228 		}
229 
230 		/* arrange to (re)open the socket if necessary */
231 		if (refusingconnections)
232 		{
233 			(void) opendaemonsocket(FALSE);
234 			refusingconnections = FALSE;
235 		}
236 
237 #if XDEBUG
238 		/* check for disaster */
239 		{
240 			char jbuf[MAXHOSTNAMELEN];
241 			extern void dumpstate __P((char *));
242 
243 			expand("\201j", jbuf, sizeof jbuf, e);
244 			if (!wordinclass(jbuf, 'w'))
245 			{
246 				dumpstate("daemon lost $j");
247 				sm_syslog(LOG_ALERT, NOQID,
248 					"daemon process doesn't have $j in $=w; see syslog");
249 				abort();
250 			}
251 			else if (j_has_dot && strchr(jbuf, '.') == NULL)
252 			{
253 				dumpstate("daemon $j lost dot");
254 				sm_syslog(LOG_ALERT, NOQID,
255 					"daemon process $j lost dot; see syslog");
256 				abort();
257 			}
258 		}
259 #endif
260 
261 		/* wait for a connection */
262 		setproctitle("accepting connections on port %d",
263 			     ntohs(port));
264 #if 0
265 		/*
266 		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
267 		**  fix the SVr4 problem.  But it seems to have gone away,
268 		**  so is it worth doing this?
269 		*/
270 
271 		if (SetNonBlocking(DaemonSocket, FALSE) < 0)
272 			log an error here;
273 #endif
274 		(void) releasesignal(SIGALRM);
275 		for (;;)
276 		{
277 			fd_set readfds;
278 			struct timeval timeout;
279 
280 			FD_ZERO(&readfds);
281 			FD_SET(DaemonSocket, &readfds);
282 			timeout.tv_sec = 60;
283 			timeout.tv_usec = 0;
284 
285 			t = select(DaemonSocket + 1, FDSET_CAST &readfds,
286 				   NULL, NULL, &timeout);
287 			if (DoQueueRun)
288 				(void) runqueue(TRUE, FALSE);
289 			if (t <= 0 || !FD_ISSET(DaemonSocket, &readfds))
290 				continue;
291 
292 			errno = 0;
293 			lotherend = socksize;
294 			t = accept(DaemonSocket,
295 			    (struct sockaddr *)&RealHostAddr, &lotherend);
296 			if (t >= 0 || errno != EINTR)
297 				break;
298 		}
299 		savederrno = errno;
300 		(void) blocksignal(SIGALRM);
301 		if (t < 0)
302 		{
303 			errno = savederrno;
304 			syserr("getrequests: accept");
305 
306 			/* arrange to re-open the socket next time around */
307 			(void) close(DaemonSocket);
308 			DaemonSocket = -1;
309 			refusingconnections = TRUE;
310 			sleep(5);
311 			continue;
312 		}
313 
314 		/*
315 		**  Create a subprocess to process the mail.
316 		*/
317 
318 		if (tTd(15, 2))
319 			printf("getrequests: forking (fd = %d)\n", t);
320 
321 		/*
322 		**  Create a pipe to keep the child from writing to the
323 		**  socket until after the parent has closed it.  Otherwise
324 		**  the parent may hang if the child has closed it first.
325 		*/
326 
327 		if (pipe(pipefd) < 0)
328 			pipefd[0] = pipefd[1] = -1;
329 
330 		blocksignal(SIGCHLD);
331 		pid = fork();
332 		if (pid < 0)
333 		{
334 			syserr("daemon: cannot fork");
335 			if (pipefd[0] != -1)
336 			{
337 				(void) close(pipefd[0]);
338 				(void) close(pipefd[1]);
339 			}
340 			(void) releasesignal(SIGCHLD);
341 			sleep(10);
342 			(void) close(t);
343 			continue;
344 		}
345 
346 		if (pid == 0)
347 		{
348 			char *p;
349 			extern SIGFUNC_DECL intsig __P((int));
350 			FILE *inchannel, *outchannel;
351 
352 			/*
353 			**  CHILD -- return to caller.
354 			**	Collect verified idea of sending host.
355 			**	Verify calling user id if possible here.
356 			*/
357 
358 			(void) releasesignal(SIGALRM);
359 			(void) releasesignal(SIGCHLD);
360 			(void) setsignal(SIGCHLD, SIG_DFL);
361 			(void) setsignal(SIGHUP, intsig);
362 			(void) close(DaemonSocket);
363 			proc_list_clear();
364 
365 			/* don't schedule queue runs if we are told to ETRN */
366 			QueueIntvl = 0;
367 
368 			setproctitle("startup with %s",
369 				anynet_ntoa(&RealHostAddr));
370 
371 			if (pipefd[0] != -1)
372 			{
373 				auto char c;
374 
375 				/*
376 				**  Wait for the parent to close the write end
377 				**  of the pipe, which we will see as an EOF.
378 				**  This guarantees that we won't write to the
379 				**  socket until after the parent has closed
380 				**  the pipe.
381 				*/
382 
383 				/* close the write end of the pipe */
384 				(void) close(pipefd[1]);
385 
386 				/* we shouldn't be interrupted, but ... */
387 				while (read(pipefd[0], &c, 1) < 0 &&
388 				       errno == EINTR)
389 					continue;
390 				(void) close(pipefd[0]);
391 			}
392 
393 			/* determine host name */
394 			p = hostnamebyanyaddr(&RealHostAddr);
395 			if (strlen(p) > (SIZE_T) MAXNAME)
396 				p[MAXNAME] = '\0';
397 			RealHostName = newstr(p);
398 			setproctitle("startup with %s", p);
399 
400 			if ((inchannel = fdopen(t, "r")) == NULL ||
401 			    (t = dup(t)) < 0 ||
402 			    (outchannel = fdopen(t, "w")) == NULL)
403 			{
404 				syserr("cannot open SMTP server channel, fd=%d", t);
405 				exit(EX_OK);
406 			}
407 
408 			InChannel = inchannel;
409 			OutChannel = outchannel;
410 			DisConnected = FALSE;
411 
412 			/* open maps for check_relay ruleset */
413 			initmaps(FALSE, e);
414 
415 #ifdef XLA
416 			if (!xla_host_ok(RealHostName))
417 			{
418 				message("421 Too many SMTP sessions for this host");
419 				exit(EX_OK);
420 			}
421 #endif
422 
423 			break;
424 		}
425 
426 		/* parent -- keep track of children */
427 		proc_list_add(pid);
428 		(void) releasesignal(SIGCHLD);
429 
430 		/* close the read end of the synchronization pipe */
431 		if (pipefd[0] != -1)
432 			(void) close(pipefd[0]);
433 
434 		/* close the port so that others will hang (for a while) */
435 		(void) close(t);
436 
437 		/* release the child by closing the read end of the sync pipe */
438 		if (pipefd[1] != -1)
439 			(void) close(pipefd[1]);
440 	}
441 	if (tTd(15, 2))
442 		printf("getreq: returning\n");
443 	return;
444 }
445 /*
446 **  OPENDAEMONSOCKET -- open the SMTP socket
447 **
448 **	Deals with setting all appropriate options.  DaemonAddr must
449 **	be set up in advance.
450 **
451 **	Parameters:
452 **		firsttime -- set if this is the initial open.
453 **
454 **	Returns:
455 **		Size in bytes of the daemon socket addr.
456 **
457 **	Side Effects:
458 **		Leaves DaemonSocket set to the open socket.
459 **		Exits if the socket cannot be created.
460 */
461 
462 #define MAXOPENTRIES	10	/* maximum number of tries to open connection */
463 
464 int
465 opendaemonsocket(firsttime)
466 	bool firsttime;
467 {
468 	int on = 1;
469 	int socksize = 0;
470 	int ntries = 0;
471 	int saveerrno;
472 
473 	if (tTd(15, 2))
474 		printf("opendaemonsocket()\n");
475 
476 	do
477 	{
478 		if (ntries > 0)
479 			sleep(5);
480 		if (firsttime || DaemonSocket < 0)
481 		{
482 			DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
483 			if (DaemonSocket < 0)
484 			{
485 				saveerrno = errno;
486 				syserr("opendaemonsocket: can't create server SMTP socket");
487 			  severe:
488 				if (LogLevel > 0)
489 					sm_syslog(LOG_ALERT, NOQID,
490 						"problem creating SMTP socket");
491 				DaemonSocket = -1;
492 				continue;
493 			}
494 
495 			/* turn on network debugging? */
496 			if (tTd(15, 101))
497 				(void) setsockopt(DaemonSocket, SOL_SOCKET,
498 						  SO_DEBUG, (char *)&on,
499 						  sizeof on);
500 
501 			(void) setsockopt(DaemonSocket, SOL_SOCKET,
502 					  SO_REUSEADDR, (char *)&on, sizeof on);
503 			(void) setsockopt(DaemonSocket, SOL_SOCKET,
504 					  SO_KEEPALIVE, (char *)&on, sizeof on);
505 
506 #ifdef SO_RCVBUF
507 			if (TcpRcvBufferSize > 0)
508 			{
509 				if (setsockopt(DaemonSocket, SOL_SOCKET,
510 					       SO_RCVBUF,
511 					       (char *) &TcpRcvBufferSize,
512 					       sizeof(TcpRcvBufferSize)) < 0)
513 					syserr("opendaemonsocket: setsockopt(SO_RCVBUF)");
514 			}
515 #endif
516 
517 			switch (DaemonAddr.sa.sa_family)
518 			{
519 # if NETINET
520 			  case AF_INET:
521 				socksize = sizeof DaemonAddr.sin;
522 				break;
523 # endif
524 
525 # if NETISO
526 			  case AF_ISO:
527 				socksize = sizeof DaemonAddr.siso;
528 				break;
529 # endif
530 
531 			  default:
532 				socksize = sizeof DaemonAddr;
533 				break;
534 			}
535 
536 			if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
537 			{
538 				/* probably another daemon already */
539 				saveerrno = errno;
540 				syserr("opendaemonsocket: cannot bind");
541 				(void) close(DaemonSocket);
542 				goto severe;
543 			}
544 		}
545 		if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
546 		{
547 			saveerrno = errno;
548 			syserr("opendaemonsocket: cannot listen");
549 			(void) close(DaemonSocket);
550 			goto severe;
551 		}
552 		return socksize;
553 	} while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
554 	syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
555 	finis();
556 	return -1;  /* avoid compiler warning on IRIX */
557 }
558 /*
559 **  CLRDAEMON -- reset the daemon connection
560 **
561 **	Parameters:
562 **		none.
563 **
564 **	Returns:
565 **		none.
566 **
567 **	Side Effects:
568 **		releases any resources used by the passive daemon.
569 */
570 
571 void
572 clrdaemon()
573 {
574 	if (DaemonSocket >= 0)
575 		(void) close(DaemonSocket);
576 	DaemonSocket = -1;
577 }
578 /*
579 **  SETDAEMONOPTIONS -- set options for running the daemon
580 **
581 **	Parameters:
582 **		p -- the options line.
583 **
584 **	Returns:
585 **		none.
586 */
587 
588 void
589 setdaemonoptions(p)
590 	register char *p;
591 {
592 	if (DaemonAddr.sa.sa_family == AF_UNSPEC)
593 		DaemonAddr.sa.sa_family = AF_INET;
594 
595 	while (p != NULL)
596 	{
597 		register char *f;
598 		register char *v;
599 
600 		while (isascii(*p) && isspace(*p))
601 			p++;
602 		if (*p == '\0')
603 			break;
604 		f = p;
605 		p = strchr(p, ',');
606 		if (p != NULL)
607 			*p++ = '\0';
608 		v = strchr(f, '=');
609 		if (v == NULL)
610 			continue;
611 		while (isascii(*++v) && isspace(*v))
612 			continue;
613 		if (isascii(*f) && islower(*f))
614 			*f = toupper(*f);
615 
616 		switch (*f)
617 		{
618 		  case 'F':		/* address family */
619 			if (isascii(*v) && isdigit(*v))
620 				DaemonAddr.sa.sa_family = atoi(v);
621 #if NETINET
622 			else if (strcasecmp(v, "inet") == 0)
623 				DaemonAddr.sa.sa_family = AF_INET;
624 #endif
625 #if NETISO
626 			else if (strcasecmp(v, "iso") == 0)
627 				DaemonAddr.sa.sa_family = AF_ISO;
628 #endif
629 #if NETNS
630 			else if (strcasecmp(v, "ns") == 0)
631 				DaemonAddr.sa.sa_family = AF_NS;
632 #endif
633 #if NETX25
634 			else if (strcasecmp(v, "x.25") == 0)
635 				DaemonAddr.sa.sa_family = AF_CCITT;
636 #endif
637 			else
638 				syserr("554 Unknown address family %s in Family=option", v);
639 			break;
640 
641 		  case 'A':		/* address */
642 			switch (DaemonAddr.sa.sa_family)
643 			{
644 #if NETINET
645 			  case AF_INET:
646 				if (isascii(*v) && isdigit(*v))
647 					DaemonAddr.sin.sin_addr.s_addr = inet_addr(v);
648 				else
649 				{
650 					register struct hostent *hp;
651 
652 					hp = sm_gethostbyname(v);
653 					if (hp == NULL)
654 						syserr("554 host \"%s\" unknown", v);
655 					else
656 						bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ);
657 				}
658 				break;
659 #endif
660 
661 			  default:
662 				syserr("554 Address= option unsupported for family %d",
663 					DaemonAddr.sa.sa_family);
664 				break;
665 			}
666 			break;
667 
668 		  case 'P':		/* port */
669 			switch (DaemonAddr.sa.sa_family)
670 			{
671 #if NETISO
672 				short port;
673 #endif
674 
675 #if NETINET
676 			  case AF_INET:
677 				if (isascii(*v) && isdigit(*v))
678 					DaemonAddr.sin.sin_port = htons(atoi(v));
679 				else
680 				{
681 					register struct servent *sp;
682 
683 					sp = getservbyname(v, "tcp");
684 					if (sp == NULL)
685 						syserr("554 service \"%s\" unknown", v);
686 					else
687 						DaemonAddr.sin.sin_port = sp->s_port;
688 				}
689 				break;
690 #endif
691 
692 #if NETISO
693 			  case AF_ISO:
694 				/* assume two byte transport selector */
695 				if (isascii(*v) && isdigit(*v))
696 					port = htons(atoi(v));
697 				else
698 				{
699 					register struct servent *sp;
700 
701 					sp = getservbyname(v, "tcp");
702 					if (sp == NULL)
703 						syserr("554 service \"%s\" unknown", v);
704 					else
705 						port = sp->s_port;
706 				}
707 				bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
708 				break;
709 #endif
710 
711 			  default:
712 				syserr("554 Port= option unsupported for family %d",
713 					DaemonAddr.sa.sa_family);
714 				break;
715 			}
716 			break;
717 
718 		  case 'L':		/* listen queue size */
719 			ListenQueueSize = atoi(v);
720 			break;
721 
722 		  case 'S':		/* send buffer size */
723 			TcpSndBufferSize = atoi(v);
724 			break;
725 
726 		  case 'R':		/* receive buffer size */
727 			TcpRcvBufferSize = atoi(v);
728 			break;
729 
730 		  default:
731 			syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
732 		}
733 	}
734 }
735 /*
736 **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
737 **
738 **	Parameters:
739 **		host -- the name of the host.
740 **		port -- the port number to connect to.
741 **		mci -- a pointer to the mail connection information
742 **			structure to be filled in.
743 **		e -- the current envelope.
744 **
745 **	Returns:
746 **		An exit code telling whether the connection could be
747 **			made and if not why not.
748 **
749 **	Side Effects:
750 **		none.
751 */
752 
753 static jmp_buf	CtxConnectTimeout;
754 
755 static void
756 connecttimeout()
757 {
758 	errno = ETIMEDOUT;
759 	longjmp(CtxConnectTimeout, 1);
760 }
761 
762 SOCKADDR	CurHostAddr;		/* address of current host */
763 
764 int
765 makeconnection(host, port, mci, e)
766 	char *host;
767 	u_short port;
768 	register MCI *mci;
769 	ENVELOPE *e;
770 {
771 	register volatile int addrno = 0;
772 	register volatile int s;
773 	register struct hostent *volatile hp = (struct hostent *)NULL;
774 	SOCKADDR addr;
775 	int sav_errno;
776 	volatile int addrlen;
777 	volatile bool firstconnect;
778 	EVENT *volatile ev = NULL;
779 
780 	/*
781 	**  Set up the address for the mailer.
782 	**	Accept "[a.b.c.d]" syntax for host name.
783 	*/
784 
785 #if NAMED_BIND
786 	h_errno = 0;
787 #endif
788 	errno = 0;
789 	bzero(&CurHostAddr, sizeof CurHostAddr);
790 	SmtpPhase = mci->mci_phase = "initial connection";
791 	CurHostName = host;
792 
793 	if (host[0] == '[')
794 	{
795 #if NETINET
796 		unsigned long hid = INADDR_NONE;
797 #endif
798 		register char *p = strchr(host, ']');
799 
800 		if (p != NULL)
801 		{
802 			*p = '\0';
803 #if NETINET
804 			hid = inet_addr(&host[1]);
805 			if (hid == INADDR_NONE)
806 #endif
807 			{
808 				/* try it as a host name (avoid MX lookup) */
809 				hp = sm_gethostbyname(&host[1]);
810 				if (hp == NULL && p[-1] == '.')
811 				{
812 #if NAMED_BIND
813 					int oldopts = _res.options;
814 
815 					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
816 #endif
817 					p[-1] = '\0';
818 					hp = sm_gethostbyname(&host[1]);
819 					p[-1] = '.';
820 #if NAMED_BIND
821 					_res.options = oldopts;
822 #endif
823 				}
824 				*p = ']';
825 				goto gothostent;
826 			}
827 			*p = ']';
828 		}
829 		if (p == NULL)
830 		{
831 			extern char MsgBuf[];
832 
833 			usrerr("553 Invalid numeric domain spec \"%s\"", host);
834 			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
835 			return EX_NOHOST;
836 		}
837 #if NETINET
838 		addr.sin.sin_family = AF_INET;		/*XXX*/
839 		addr.sin.sin_addr.s_addr = hid;
840 #endif
841 	}
842 	else
843 	{
844 		/* contortion to get around SGI cc complaints */
845 		{
846 			register char *p = &host[strlen(host) - 1];
847 
848 			hp = sm_gethostbyname(host);
849 			if (hp == NULL && *p == '.')
850 			{
851 #if NAMED_BIND
852 				int oldopts = _res.options;
853 
854 				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
855 #endif
856 				*p = '\0';
857 				hp = sm_gethostbyname(host);
858 				*p = '.';
859 #if NAMED_BIND
860 				_res.options = oldopts;
861 #endif
862 			}
863 		}
864 gothostent:
865 		if (hp == NULL)
866 		{
867 #if NAMED_BIND
868 			/* check for name server timeouts */
869 			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
870 			    (errno == ECONNREFUSED && UseNameServer))
871 			{
872 				mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
873 				return EX_TEMPFAIL;
874 			}
875 #endif
876 			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
877 			return (EX_NOHOST);
878 		}
879 		addr.sa.sa_family = hp->h_addrtype;
880 		switch (hp->h_addrtype)
881 		{
882 #if NETINET
883 		  case AF_INET:
884 			bcopy(hp->h_addr,
885 				&addr.sin.sin_addr,
886 				INADDRSZ);
887 			break;
888 #endif
889 
890 		  default:
891 			if (hp->h_length > sizeof addr.sa.sa_data)
892 			{
893 				syserr("makeconnection: long sa_data: family %d len %d",
894 					hp->h_addrtype, hp->h_length);
895 				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
896 				return EX_NOHOST;
897 			}
898 			bcopy(hp->h_addr,
899 				addr.sa.sa_data,
900 				hp->h_length);
901 			break;
902 		}
903 		addrno = 1;
904 	}
905 
906 	/*
907 	**  Determine the port number.
908 	*/
909 
910 	if (port == 0)
911 	{
912 		register struct servent *sp = getservbyname("smtp", "tcp");
913 
914 		if (sp == NULL)
915 		{
916 			if (LogLevel > 2)
917 				sm_syslog(LOG_ERR, NOQID,
918 					"makeconnection: service \"smtp\" unknown");
919 			port = htons(25);
920 		}
921 		else
922 			port = sp->s_port;
923 	}
924 
925 	switch (addr.sa.sa_family)
926 	{
927 #if NETINET
928 	  case AF_INET:
929 		addr.sin.sin_port = port;
930 		addrlen = sizeof (struct sockaddr_in);
931 		break;
932 #endif
933 
934 #if NETISO
935 	  case AF_ISO:
936 		/* assume two byte transport selector */
937 		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
938 		addrlen = sizeof (struct sockaddr_iso);
939 		break;
940 #endif
941 
942 	  default:
943 		syserr("Can't connect to address family %d", addr.sa.sa_family);
944 		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
945 		return (EX_NOHOST);
946 	}
947 
948 	/*
949 	**  Try to actually open the connection.
950 	*/
951 
952 #ifdef XLA
953 	/* if too many connections, don't bother trying */
954 	if (!xla_noqueue_ok(host))
955 		return EX_TEMPFAIL;
956 #endif
957 
958 	firstconnect = TRUE;
959 	for (;;)
960 	{
961 		if (tTd(16, 1))
962 			printf("makeconnection (%s [%s])\n",
963 				host, anynet_ntoa(&addr));
964 
965 		/* save for logging */
966 		CurHostAddr = addr;
967 
968 		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
969 		{
970 			int rport = IPPORT_RESERVED - 1;
971 
972 			s = rresvport(&rport);
973 		}
974 		else
975 		{
976 			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
977 		}
978 		if (s < 0)
979 		{
980 			sav_errno = errno;
981 			syserr("makeconnection: cannot create socket");
982 #ifdef XLA
983 			xla_host_end(host);
984 #endif
985 			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
986 			return EX_TEMPFAIL;
987 		}
988 
989 #ifdef SO_SNDBUF
990 		if (TcpSndBufferSize > 0)
991 		{
992 			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
993 				       (char *) &TcpSndBufferSize,
994 				       sizeof(TcpSndBufferSize)) < 0)
995 				syserr("makeconnection: setsockopt(SO_SNDBUF)");
996 		}
997 #endif
998 
999 		if (tTd(16, 1))
1000 			printf("makeconnection: fd=%d\n", s);
1001 
1002 		/* turn on network debugging? */
1003 		if (tTd(16, 101))
1004 		{
1005 			int on = 1;
1006 			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
1007 					  (char *)&on, sizeof on);
1008 		}
1009 		if (e->e_xfp != NULL)
1010 			(void) fflush(e->e_xfp);		/* for debugging */
1011 		errno = 0;					/* for debugging */
1012 
1013 		/*
1014 		**  Linux seems to hang in connect for 90 minutes (!!!).
1015 		**  Time out the connect to avoid this problem.
1016 		*/
1017 
1018 		if (setjmp(CtxConnectTimeout) == 0)
1019 		{
1020 			int i;
1021 
1022 			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
1023 				ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
1024 			else if (TimeOuts.to_connect != 0)
1025 				ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
1026 			else
1027 				ev = NULL;
1028 
1029 #if _FFR_CONNECTONLYTO_OPTION
1030 			/* for testing */
1031 			if (ConnectOnlyTo != 0)
1032 				addr.sin.sin_addr.s_addr = ConnectOnlyTo;
1033 #endif
1034 			i = connect(s, (struct sockaddr *) &addr, addrlen);
1035 			sav_errno = errno;
1036 			if (ev != NULL)
1037 				clrevent(ev);
1038 			if (i >= 0)
1039 				break;
1040 		}
1041 		else
1042 			sav_errno = errno;
1043 
1044 		/* if running demand-dialed connection, try again */
1045 		if (DialDelay > 0 && firstconnect)
1046 		{
1047 			if (tTd(16, 1))
1048 				printf("Connect failed (%s); trying again...\n",
1049 					errstring(sav_errno));
1050 			firstconnect = FALSE;
1051 			sleep(DialDelay);
1052 			continue;
1053 		}
1054 
1055 		/* couldn't connect.... figure out why */
1056 		(void) close(s);
1057 
1058 		if (LogLevel >= 14)
1059 			sm_syslog(LOG_INFO, e->e_id,
1060 				  "makeconnection (%s [%s]) failed: %s",
1061 				  host, anynet_ntoa(&addr),
1062 				  errstring(sav_errno));
1063 
1064 		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
1065 		{
1066 			if (tTd(16, 1))
1067 				printf("Connect failed (%s); trying new address....\n",
1068 					errstring(sav_errno));
1069 			switch (addr.sa.sa_family)
1070 			{
1071 #if NETINET
1072 			  case AF_INET:
1073 				bcopy(hp->h_addr_list[addrno++],
1074 				      &addr.sin.sin_addr,
1075 				      INADDRSZ);
1076 				break;
1077 #endif
1078 
1079 			  default:
1080 				bcopy(hp->h_addr_list[addrno++],
1081 					addr.sa.sa_data,
1082 					hp->h_length);
1083 				break;
1084 			}
1085 			continue;
1086 		}
1087 
1088 		/* couldn't open connection */
1089 #ifdef XLA
1090 		xla_host_end(host);
1091 #endif
1092 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
1093 		return EX_TEMPFAIL;
1094 	}
1095 
1096 	/* connection ok, put it into canonical form */
1097 	if ((mci->mci_out = fdopen(s, "w")) == NULL ||
1098 	    (s = dup(s)) < 0 ||
1099 	    (mci->mci_in = fdopen(s, "r")) == NULL)
1100 	{
1101 		syserr("cannot open SMTP client channel, fd=%d", s);
1102 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
1103 		return EX_TEMPFAIL;
1104 	}
1105 
1106 	mci_setstat(mci, EX_OK, NULL, NULL);
1107 	return (EX_OK);
1108 }
1109 /*
1110 **  MYHOSTNAME -- return the name of this host.
1111 **
1112 **	Parameters:
1113 **		hostbuf -- a place to return the name of this host.
1114 **		size -- the size of hostbuf.
1115 **
1116 **	Returns:
1117 **		A list of aliases for this host.
1118 **
1119 **	Side Effects:
1120 **		Adds numeric codes to $=w.
1121 */
1122 
1123 struct hostent *
1124 myhostname(hostbuf, size)
1125 	char hostbuf[];
1126 	int size;
1127 {
1128 	register struct hostent *hp;
1129 
1130 	if (gethostname(hostbuf, size) < 0)
1131 	{
1132 		(void) strcpy(hostbuf, "localhost");
1133 	}
1134 	hp = sm_gethostbyname(hostbuf);
1135 	if (hp == NULL)
1136 		return NULL;
1137 	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
1138 	{
1139 		(void) strncpy(hostbuf, hp->h_name, size - 1);
1140 		hostbuf[size - 1] = '\0';
1141 	}
1142 
1143 	/*
1144 	**  If there is still no dot in the name, try looking for a
1145 	**  dotted alias.
1146 	*/
1147 
1148 	if (strchr(hostbuf, '.') == NULL)
1149 	{
1150 		char **ha;
1151 
1152 		for (ha = hp->h_aliases; *ha != NULL; ha++)
1153 		{
1154 			if (strchr(*ha, '.') != NULL)
1155 			{
1156 				(void) strncpy(hostbuf, *ha, size - 1);
1157 				hostbuf[size - 1] = '\0';
1158 				break;
1159 			}
1160 		}
1161 	}
1162 
1163 	/*
1164 	**  If _still_ no dot, wait for a while and try again -- it is
1165 	**  possible that some service is starting up.  This can result
1166 	**  in excessive delays if the system is badly configured, but
1167 	**  there really isn't a way around that, particularly given that
1168 	**  the config file hasn't been read at this point.
1169 	**  All in all, a bit of a mess.
1170 	*/
1171 
1172 	if (strchr(hostbuf, '.') == NULL &&
1173 	    !getcanonname(hostbuf, size, TRUE))
1174 	{
1175 		sm_syslog(LOG_CRIT, NOQID,
1176 			"My unqualified host name (%s) unknown; sleeping for retry",
1177 			hostbuf);
1178 		message("My unqualified host name (%s) unknown; sleeping for retry",
1179 			hostbuf);
1180 		sleep(60);
1181 		if (!getcanonname(hostbuf, size, TRUE))
1182 		{
1183 			sm_syslog(LOG_ALERT, NOQID,
1184 				"unable to qualify my own domain name (%s) -- using short name",
1185 				hostbuf);
1186 			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
1187 				hostbuf);
1188 		}
1189 	}
1190 	return (hp);
1191 }
1192 /*
1193 **  ADDRCMP -- compare two host addresses
1194 **
1195 **	Parameters:
1196 **		hp -- hostent structure for the first address
1197 **		ha -- actual first address
1198 **		sa -- second address
1199 **
1200 **	Returns:
1201 **		0 -- if ha and sa match
1202 **		else -- they don't match
1203 */
1204 
1205 int
1206 addrcmp(hp, ha, sa)
1207 	struct hostent *hp;
1208 	char *ha;
1209 	SOCKADDR *sa;
1210 {
1211 	switch (sa->sa.sa_family)
1212 	{
1213 	  case AF_INET:
1214 		if (hp->h_addrtype == AF_INET)
1215 			return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length);
1216 		break;
1217 
1218 	}
1219 	return -1;
1220 }
1221 /*
1222 **  GETAUTHINFO -- get the real host name asociated with a file descriptor
1223 **
1224 **	Uses RFC1413 protocol to try to get info from the other end.
1225 **
1226 **	Parameters:
1227 **		fd -- the descriptor
1228 **		may_be_forged -- an outage that is set to TRUE if the
1229 **			forward lookup of RealHostName does not match
1230 **			RealHostAddr; set to FALSE if they do match.
1231 **
1232 **	Returns:
1233 **		The user@host information associated with this descriptor.
1234 */
1235 
1236 static jmp_buf	CtxAuthTimeout;
1237 
1238 static void
1239 authtimeout()
1240 {
1241 	longjmp(CtxAuthTimeout, 1);
1242 }
1243 
1244 char *
1245 getauthinfo(fd, may_be_forged)
1246 	int fd;
1247 	bool *may_be_forged;
1248 {
1249 	SOCKADDR_LEN_T falen;
1250 	register char *volatile p = NULL;
1251 	SOCKADDR la;
1252 	SOCKADDR_LEN_T lalen;
1253 	register struct servent *sp;
1254 	volatile int s;
1255 	int i = 0;
1256 	EVENT *ev;
1257 	int nleft;
1258 	struct hostent *hp;
1259 	char *ostype = NULL;
1260 	char **ha;
1261 	char ibuf[MAXNAME + 1];
1262 	static char hbuf[MAXNAME * 2 + 11];
1263 
1264 	*may_be_forged = FALSE;
1265 	falen = sizeof RealHostAddr;
1266 	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
1267 	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
1268 	{
1269 		if (i < 0 && errno != ENOTSOCK)
1270 			return NULL;
1271 		(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
1272 			RealUserName);
1273 		if (tTd(9, 1))
1274 			printf("getauthinfo: %s\n", hbuf);
1275 		return hbuf;
1276 	}
1277 
1278 	if (RealHostName == NULL)
1279 	{
1280 		/* translate that to a host name */
1281 		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
1282 		if (strlen(RealHostName) > MAXNAME)
1283 			RealHostName[MAXNAME - 1] = '\0';
1284 	}
1285 
1286 	/* cross check RealHostName with forward DNS lookup */
1287 	if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
1288 	    RealHostName[0] == '[')
1289 	{
1290 		/*
1291 		** address is not a socket or have an
1292 		** IP address with no forward lookup
1293 		*/
1294 		*may_be_forged = FALSE;
1295 	}
1296 	else
1297 	{
1298 		/* try to match the reverse against the forward lookup */
1299 		hp = sm_gethostbyname(RealHostName);
1300 
1301 		if (hp == NULL)
1302 			*may_be_forged = TRUE;
1303 		else
1304 		{
1305 			for (ha = hp->h_addr_list; *ha != NULL; ha++)
1306 				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
1307 					break;
1308 			*may_be_forged = *ha == NULL;
1309 		}
1310 	}
1311 
1312 	if (TimeOuts.to_ident == 0)
1313 		goto noident;
1314 
1315 	lalen = sizeof la;
1316 	if (RealHostAddr.sa.sa_family != AF_INET ||
1317 	    getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
1318 	    la.sa.sa_family != AF_INET)
1319 	{
1320 		/* no ident info */
1321 		goto noident;
1322 	}
1323 
1324 	/* create ident query */
1325 	(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
1326 		ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
1327 
1328 	/* create local address */
1329 	la.sin.sin_port = 0;
1330 
1331 	/* create foreign address */
1332 	sp = getservbyname("auth", "tcp");
1333 	if (sp != NULL)
1334 		RealHostAddr.sin.sin_port = sp->s_port;
1335 	else
1336 		RealHostAddr.sin.sin_port = htons(113);
1337 
1338 	s = -1;
1339 	if (setjmp(CtxAuthTimeout) != 0)
1340 	{
1341 		if (s >= 0)
1342 			(void) close(s);
1343 		goto noident;
1344 	}
1345 
1346 	/* put a timeout around the whole thing */
1347 	ev = setevent(TimeOuts.to_ident, authtimeout, 0);
1348 
1349 	/* connect to foreign IDENT server using same address as SMTP socket */
1350 	s = socket(AF_INET, SOCK_STREAM, 0);
1351 	if (s < 0)
1352 	{
1353 		clrevent(ev);
1354 		goto noident;
1355 	}
1356 	if (bind(s, &la.sa, sizeof la.sin) < 0 ||
1357 	    connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
1358 	{
1359 		goto closeident;
1360 	}
1361 
1362 	if (tTd(9, 10))
1363 		printf("getauthinfo: sent %s", ibuf);
1364 
1365 	/* send query */
1366 	if (write(s, ibuf, strlen(ibuf)) < 0)
1367 		goto closeident;
1368 
1369 	/* get result */
1370 	p = &ibuf[0];
1371 	nleft = sizeof ibuf - 1;
1372 	while ((i = read(s, p, nleft)) > 0)
1373 	{
1374 		p += i;
1375 		nleft -= i;
1376 		*p = '\0';
1377 		if (strchr(ibuf, '\n') != NULL)
1378 			break;
1379 	}
1380 	(void) close(s);
1381 	clrevent(ev);
1382 	if (i < 0 || p == &ibuf[0])
1383 		goto noident;
1384 
1385 	if (*--p == '\n' && *--p == '\r')
1386 		p--;
1387 	*++p = '\0';
1388 
1389 	if (tTd(9, 3))
1390 		printf("getauthinfo:  got %s\n", ibuf);
1391 
1392 	/* parse result */
1393 	p = strchr(ibuf, ':');
1394 	if (p == NULL)
1395 	{
1396 		/* malformed response */
1397 		goto noident;
1398 	}
1399 	while (isascii(*++p) && isspace(*p))
1400 		continue;
1401 	if (strncasecmp(p, "userid", 6) != 0)
1402 	{
1403 		/* presumably an error string */
1404 		goto noident;
1405 	}
1406 	p += 6;
1407 	while (isascii(*p) && isspace(*p))
1408 		p++;
1409 	if (*p++ != ':')
1410 	{
1411 		/* either useridxx or malformed response */
1412 		goto noident;
1413 	}
1414 
1415 	/* p now points to the OSTYPE field */
1416 	while (isascii(*p) && isspace(*p))
1417 		p++;
1418 	ostype = p;
1419 	p = strchr(p, ':');
1420 	if (p == NULL)
1421 	{
1422 		/* malformed response */
1423 		goto noident;
1424 	}
1425 	else
1426 	{
1427 		char *charset;
1428 
1429 		*p = '\0';
1430 		charset = strchr(ostype, ',');
1431 		if (charset != NULL)
1432 			*charset = '\0';
1433 	}
1434 
1435 	/* 1413 says don't do this -- but it's broken otherwise */
1436 	while (isascii(*++p) && isspace(*p))
1437 		continue;
1438 
1439 	/* p now points to the authenticated name -- copy carefully */
1440 	if (strncasecmp(ostype, "other", 5) == 0 &&
1441 	    (ostype[5] == ' ' || ostype[5] == '\0'))
1442 	{
1443 		snprintf(hbuf, sizeof hbuf, "IDENT:");
1444 		cleanstrcpy(&hbuf[6], p, MAXNAME);
1445 	}
1446 	else
1447 		cleanstrcpy(hbuf, p, MAXNAME);
1448 	i = strlen(hbuf);
1449 	snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
1450 		 RealHostName == NULL ? "localhost" : RealHostName);
1451 	goto postident;
1452 
1453 closeident:
1454 	(void) close(s);
1455 	clrevent(ev);
1456 
1457 noident:
1458 	if (RealHostName == NULL)
1459 	{
1460 		if (tTd(9, 1))
1461 			printf("getauthinfo: NULL\n");
1462 		return NULL;
1463 	}
1464 	snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
1465 
1466 postident:
1467 #if IP_SRCROUTE
1468 # ifndef GET_IPOPT_DST
1469 #  define GET_IPOPT_DST(dst)	(dst)
1470 # endif
1471 	/*
1472 	**  Extract IP source routing information.
1473 	**
1474 	**	Format of output for a connection from site a through b
1475 	**	through c to d:
1476 	**		loose:      @site-c@site-b:site-a
1477 	**		strict:	   !@site-c@site-b:site-a
1478 	**
1479 	**	o - pointer within ipopt_list structure.
1480 	**	q - pointer within ls/ss rr route data
1481 	**	p - pointer to hbuf
1482 	*/
1483 
1484 	if (RealHostAddr.sa.sa_family == AF_INET)
1485 	{
1486 		SOCKOPT_LEN_T ipoptlen;
1487 		int j;
1488 		u_char *q;
1489 		u_char *o;
1490 		int l;
1491 		struct in_addr addr;
1492 		struct ipoption ipopt;
1493 
1494 		ipoptlen = sizeof ipopt;
1495 		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
1496 			       (char *) &ipopt, &ipoptlen) < 0)
1497 			goto noipsr;
1498 		if (ipoptlen == 0)
1499 			goto noipsr;
1500 		o = (u_char *) ipopt.ipopt_list;
1501 		while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
1502 		{
1503 			switch (*o)
1504 			{
1505 			  case IPOPT_EOL:
1506 				o = NULL;
1507 				break;
1508 
1509 			  case IPOPT_NOP:
1510 				o++;
1511 				break;
1512 
1513 			  case IPOPT_SSRR:
1514 			  case IPOPT_LSRR:
1515 				/*
1516 				**  Source routing.
1517 				**	o[0] is the option type (loose/strict).
1518 				**	o[1] is the length of this option,
1519 				**		including option type and
1520 				**		length.
1521 				**	o[2] is the pointer into the route
1522 				**		data.
1523 				**	o[3] begins the route data.
1524 				*/
1525 
1526 				p = &hbuf[strlen(hbuf)];
1527 				l = sizeof hbuf - (hbuf - p) - 6;
1528 				snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
1529 				    *o == IPOPT_SSRR ? "!" : "",
1530 				    l > 240 ? 120 : l / 2,
1531 				    inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst)));
1532 				i = strlen(p);
1533 				p += i;
1534 				l -= strlen(p);
1535 
1536 				j = o[1] / sizeof(struct in_addr) - 1;
1537 
1538 				/* q skips length and router pointer to data */
1539 				q = &o[3];
1540 				for ( ; j >= 0; j--)
1541 				{
1542 					memcpy(&addr, q, sizeof(addr));
1543 					snprintf(p, SPACELEFT(hbuf, p),
1544 						"%c%.*s",
1545 						j != 0 ? '@' : ':',
1546 						l > 240 ? 120 :
1547 						    j == 0 ? l : l / 2,
1548 						inet_ntoa(addr));
1549 					i = strlen(p);
1550 					p += i;
1551 					l -= i + 1;
1552 					q += sizeof(struct in_addr);
1553 				}
1554 				o += o[1];
1555 				break;
1556 
1557 			  default:
1558 				/* Skip over option */
1559 				o += o[1];
1560 				break;
1561 			}
1562 		}
1563 		snprintf(p, SPACELEFT(hbuf, p), "]");
1564 		goto postipsr;
1565 	}
1566 
1567 noipsr:
1568 #endif
1569 	if (RealHostName != NULL && RealHostName[0] != '[')
1570 	{
1571 		p = &hbuf[strlen(hbuf)];
1572 		(void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
1573 			anynet_ntoa(&RealHostAddr));
1574 	}
1575 	if (*may_be_forged)
1576 	{
1577 		p = &hbuf[strlen(hbuf)];
1578 		(void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
1579 	}
1580 
1581 #if IP_SRCROUTE
1582 postipsr:
1583 #endif
1584 	if (tTd(9, 1))
1585 		printf("getauthinfo: %s\n", hbuf);
1586 	return hbuf;
1587 }
1588 /*
1589 **  HOST_MAP_LOOKUP -- turn a hostname into canonical form
1590 **
1591 **	Parameters:
1592 **		map -- a pointer to this map.
1593 **		name -- the (presumably unqualified) hostname.
1594 **		av -- unused -- for compatibility with other mapping
1595 **			functions.
1596 **		statp -- an exit status (out parameter) -- set to
1597 **			EX_TEMPFAIL if the name server is unavailable.
1598 **
1599 **	Returns:
1600 **		The mapping, if found.
1601 **		NULL if no mapping found.
1602 **
1603 **	Side Effects:
1604 **		Looks up the host specified in hbuf.  If it is not
1605 **		the canonical name for that host, return the canonical
1606 **		name (unless MF_MATCHONLY is set, which will cause the
1607 **		status only to be returned).
1608 */
1609 
1610 char *
1611 host_map_lookup(map, name, av, statp)
1612 	MAP *map;
1613 	char *name;
1614 	char **av;
1615 	int *statp;
1616 {
1617 	register struct hostent *hp;
1618 	struct in_addr in_addr;
1619 	char *cp;
1620 	register STAB *s;
1621 	char hbuf[MAXNAME + 1];
1622 
1623 	/*
1624 	**  See if we have already looked up this name.  If so, just
1625 	**  return it.
1626 	*/
1627 
1628 	s = stab(name, ST_NAMECANON, ST_ENTER);
1629 	if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
1630 	{
1631 		if (tTd(9, 1))
1632 			printf("host_map_lookup(%s) => CACHE %s\n",
1633 			       name,
1634 			       s->s_namecanon.nc_cname == NULL
1635 					? "NULL"
1636 					: s->s_namecanon.nc_cname);
1637 		errno = s->s_namecanon.nc_errno;
1638 #if NAMED_BIND
1639 		h_errno = s->s_namecanon.nc_herrno;
1640 #endif
1641 		*statp = s->s_namecanon.nc_stat;
1642 		if (*statp == EX_TEMPFAIL)
1643 		{
1644 			CurEnv->e_status = "4.4.3";
1645 			message("851 %s: Name server timeout",
1646 				shortenstring(name, 33));
1647 		}
1648 		if (*statp != EX_OK)
1649 			return NULL;
1650 		if (s->s_namecanon.nc_cname == NULL)
1651 		{
1652 			syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
1653 				name,
1654 				s->s_namecanon.nc_errno,
1655 				s->s_namecanon.nc_herrno);
1656 			return NULL;
1657 		}
1658 		if (bitset(MF_MATCHONLY, map->map_mflags))
1659 			cp = map_rewrite(map, name, strlen(name), NULL);
1660 		else
1661 			cp = map_rewrite(map,
1662 					 s->s_namecanon.nc_cname,
1663 					 strlen(s->s_namecanon.nc_cname),
1664 					 av);
1665 		return cp;
1666 	}
1667 
1668 	/*
1669 	**  If we are running without a regular network connection (usually
1670 	**  dial-on-demand) and we are just queueing, we want to avoid DNS
1671 	**  lookups because those could try to connect to a server.
1672 	*/
1673 
1674 	if (CurEnv->e_sendmode == SM_DEFER)
1675 	{
1676 		if (tTd(9, 1))
1677 			printf("host_map_lookup(%s) => DEFERRED\n", name);
1678 		*statp = EX_TEMPFAIL;
1679 		return NULL;
1680 	}
1681 
1682 	/*
1683 	**  If first character is a bracket, then it is an address
1684 	**  lookup.  Address is copied into a temporary buffer to
1685 	**  strip the brackets and to preserve name if address is
1686 	**  unknown.
1687 	*/
1688 
1689 	if (*name != '[')
1690 	{
1691 		if (tTd(9, 1))
1692 			printf("host_map_lookup(%s) => ", name);
1693 		s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
1694 		snprintf(hbuf, sizeof hbuf, "%s", name);
1695 		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
1696 		{
1697 			if (tTd(9, 1))
1698 				printf("%s\n", hbuf);
1699 			s->s_namecanon.nc_stat = EX_OK;
1700 			s->s_namecanon.nc_cname = newstr(hbuf);
1701 			if (bitset(MF_MATCHONLY, map->map_mflags))
1702 				cp = map_rewrite(map, name, strlen(name), NULL);
1703 			else
1704 				cp = map_rewrite(map, hbuf, strlen(hbuf), av);
1705 			return cp;
1706 		}
1707 		else
1708 		{
1709 			s->s_namecanon.nc_errno = errno;
1710 #if NAMED_BIND
1711 			s->s_namecanon.nc_herrno = h_errno;
1712 			if (tTd(9, 1))
1713 				printf("FAIL (%d)\n", h_errno);
1714 			switch (h_errno)
1715 			{
1716 			  case TRY_AGAIN:
1717 				if (UseNameServer)
1718 				{
1719 					CurEnv->e_status = "4.4.3";
1720 					message("851 %s: Name server timeout",
1721 						shortenstring(name, 33));
1722 				}
1723 				*statp = EX_TEMPFAIL;
1724 				break;
1725 
1726 			  case HOST_NOT_FOUND:
1727 			  case NO_DATA:
1728 				*statp = EX_NOHOST;
1729 				break;
1730 
1731 			  case NO_RECOVERY:
1732 				*statp = EX_SOFTWARE;
1733 				break;
1734 
1735 			  default:
1736 				*statp = EX_UNAVAILABLE;
1737 				break;
1738 			}
1739 #else
1740 			if (tTd(9, 1))
1741 				printf("FAIL\n");
1742 			*statp = EX_NOHOST;
1743 #endif
1744 			s->s_namecanon.nc_stat = *statp;
1745 			return NULL;
1746 		}
1747 	}
1748 	if ((cp = strchr(name, ']')) == NULL)
1749 		return (NULL);
1750 	*cp = '\0';
1751 	in_addr.s_addr = inet_addr(&name[1]);
1752 	*cp = ']';
1753 
1754 	/* nope -- ask the name server */
1755 	hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET);
1756 	s->s_namecanon.nc_errno = errno;
1757 #if NAMED_BIND
1758 	s->s_namecanon.nc_herrno = h_errno;
1759 #endif
1760 	s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
1761 	if (hp == NULL)
1762 	{
1763 		s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1764 		return (NULL);
1765 	}
1766 
1767 	/* found a match -- copy out */
1768 	hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE);
1769 	s->s_namecanon.nc_stat = *statp = EX_OK;
1770 	s->s_namecanon.nc_cname = newstr(hp->h_name);
1771 	if (bitset(MF_MATCHONLY, map->map_mflags))
1772 		cp = map_rewrite(map, name, strlen(name), NULL);
1773 	else
1774 		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1775 	return cp;
1776 }
1777 
1778 # else /* DAEMON */
1779 /* code for systems without sophisticated networking */
1780 
1781 /*
1782 **  MYHOSTNAME -- stub version for case of no daemon code.
1783 **
1784 **	Can't convert to upper case here because might be a UUCP name.
1785 **
1786 **	Mark, you can change this to be anything you want......
1787 */
1788 
1789 char **
1790 myhostname(hostbuf, size)
1791 	char hostbuf[];
1792 	int size;
1793 {
1794 	register FILE *f;
1795 
1796 	hostbuf[0] = '\0';
1797 	f = fopen("/usr/include/whoami", "r");
1798 	if (f != NULL)
1799 	{
1800 		(void) fgets(hostbuf, size, f);
1801 		fixcrlf(hostbuf, TRUE);
1802 		(void) fclose(f);
1803 	}
1804 	return (NULL);
1805 }
1806 /*
1807 **  GETAUTHINFO -- get the real host name asociated with a file descriptor
1808 **
1809 **	Parameters:
1810 **		fd -- the descriptor
1811 **		may_be_forged -- an outage that is set to TRUE if the
1812 **			forward lookup of RealHostName does not match
1813 **			RealHostAddr; set to FALSE if they do match.
1814 **
1815 **	Returns:
1816 **		The host name associated with this descriptor, if it can
1817 **			be determined.
1818 **		NULL otherwise.
1819 **
1820 **	Side Effects:
1821 **		none
1822 */
1823 
1824 char *
1825 getauthinfo(fd, may_be_forged)
1826 	int fd;
1827 	bool *may_be_forged;
1828 {
1829 	*may_be_forged = FALSE;
1830 	return NULL;
1831 }
1832 /*
1833 **  MAPHOSTNAME -- turn a hostname into canonical form
1834 **
1835 **	Parameters:
1836 **		map -- a pointer to the database map.
1837 **		name -- a buffer containing a hostname.
1838 **		avp -- a pointer to a (cf file defined) argument vector.
1839 **		statp -- an exit status (out parameter).
1840 **
1841 **	Returns:
1842 **		mapped host name
1843 **		FALSE otherwise.
1844 **
1845 **	Side Effects:
1846 **		Looks up the host specified in name.  If it is not
1847 **		the canonical name for that host, replace it with
1848 **		the canonical name.  If the name is unknown, or it
1849 **		is already the canonical name, leave it unchanged.
1850 */
1851 
1852 /*ARGSUSED*/
1853 char *
1854 host_map_lookup(map, name, avp, statp)
1855 	MAP *map;
1856 	char *name;
1857 	char **avp;
1858 	char *statp;
1859 {
1860 	register struct hostent *hp;
1861 	char *cp;
1862 
1863 	hp = sm_gethostbyname(name);
1864 	if (hp == NULL)
1865 	{
1866 		*statp = EX_NOHOST;
1867 		return NULL;
1868 	}
1869 	if (bitset(MF_MATCHONLY, map->map_mflags))
1870 		cp = map_rewrite(map, name, strlen(name), NULL);
1871 	else
1872 		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
1873 	return cp;
1874 }
1875 
1876 #endif /* DAEMON */
1877 /*
1878 **  HOST_MAP_INIT -- initialize host class structures
1879 */
1880 
1881 bool
1882 host_map_init(map, args)
1883 	MAP *map;
1884 	char *args;
1885 {
1886 	register char *p = args;
1887 
1888 	for (;;)
1889 	{
1890 		while (isascii(*p) && isspace(*p))
1891 			p++;
1892 		if (*p != '-')
1893 			break;
1894 		switch (*++p)
1895 		{
1896 		  case 'a':
1897 			map->map_app = ++p;
1898 			break;
1899 
1900 		  case 'T':
1901 			map->map_tapp = ++p;
1902 			break;
1903 
1904 		  case 'm':
1905 			map->map_mflags |= MF_MATCHONLY;
1906 			break;
1907 
1908 		  case 't':
1909 			map->map_mflags |= MF_NODEFER;
1910 			break;
1911 		}
1912 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
1913 			p++;
1914 		if (*p != '\0')
1915 			*p++ = '\0';
1916 	}
1917 	if (map->map_app != NULL)
1918 		map->map_app = newstr(map->map_app);
1919 	if (map->map_tapp != NULL)
1920 		map->map_tapp = newstr(map->map_tapp);
1921 	return TRUE;
1922 }
1923 /*
1924 **  ANYNET_NTOA -- convert a network address to printable form.
1925 **
1926 **	Parameters:
1927 **		sap -- a pointer to a sockaddr structure.
1928 **
1929 **	Returns:
1930 **		A printable version of that sockaddr.
1931 */
1932 
1933 #ifdef USE_SOCK_STREAM
1934 
1935 #if NETLINK
1936 # include <net/if_dl.h>
1937 #endif
1938 
1939 char *
1940 anynet_ntoa(sap)
1941 	register SOCKADDR *sap;
1942 {
1943 	register char *bp;
1944 	register char *ap;
1945 	int l;
1946 	static char buf[100];
1947 
1948 	/* check for null/zero family */
1949 	if (sap == NULL)
1950 		return "NULLADDR";
1951 	if (sap->sa.sa_family == 0)
1952 		return "0";
1953 
1954 	switch (sap->sa.sa_family)
1955 	{
1956 #if NETUNIX
1957 	  case AF_UNIX:
1958 	  	if (sap->sunix.sun_path[0] != '\0')
1959 	  		snprintf(buf, sizeof buf, "[UNIX: %.64s]",
1960 				sap->sunix.sun_path);
1961 	  	else
1962 	  		snprintf(buf, sizeof buf, "[UNIX: localhost]");
1963 		return buf;
1964 #endif
1965 
1966 #if NETINET
1967 	  case AF_INET:
1968 		return inet_ntoa(sap->sin.sin_addr);
1969 #endif
1970 
1971 #if NETLINK
1972 	  case AF_LINK:
1973 		snprintf(buf, sizeof buf, "[LINK: %s]",
1974 			link_ntoa((struct sockaddr_dl *) &sap->sa));
1975 		return buf;
1976 #endif
1977 	  default:
1978 		/* this case is needed when nothing is #defined */
1979 		/* in order to keep the switch syntactically correct */
1980 		break;
1981 	}
1982 
1983 	/* unknown family -- just dump bytes */
1984 	(void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
1985 	bp = &buf[strlen(buf)];
1986 	ap = sap->sa.sa_data;
1987 	for (l = sizeof sap->sa.sa_data; --l >= 0; )
1988 	{
1989 		(void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
1990 		bp += 3;
1991 	}
1992 	*--bp = '\0';
1993 	return buf;
1994 }
1995 /*
1996 **  HOSTNAMEBYANYADDR -- return name of host based on address
1997 **
1998 **	Parameters:
1999 **		sap -- SOCKADDR pointer
2000 **
2001 **	Returns:
2002 **		text representation of host name.
2003 **
2004 **	Side Effects:
2005 **		none.
2006 */
2007 
2008 char *
2009 hostnamebyanyaddr(sap)
2010 	register SOCKADDR *sap;
2011 {
2012 	register struct hostent *hp;
2013 	int saveretry;
2014 
2015 #if NAMED_BIND
2016 	/* shorten name server timeout to avoid higher level timeouts */
2017 	saveretry = _res.retry;
2018 	_res.retry = 3;
2019 #endif /* NAMED_BIND */
2020 
2021 	switch (sap->sa.sa_family)
2022 	{
2023 #if NETINET
2024 	  case AF_INET:
2025 		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
2026 			INADDRSZ,
2027 			AF_INET);
2028 		break;
2029 #endif
2030 
2031 #if NETISO
2032 	  case AF_ISO:
2033 		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
2034 			sizeof sap->siso.siso_addr,
2035 			AF_ISO);
2036 		break;
2037 #endif
2038 
2039 #if NETUNIX
2040 	  case AF_UNIX:
2041 		hp = NULL;
2042 		break;
2043 #endif
2044 
2045 	  default:
2046 		hp = sm_gethostbyaddr(sap->sa.sa_data,
2047 			   sizeof sap->sa.sa_data,
2048 			   sap->sa.sa_family);
2049 		break;
2050 	}
2051 
2052 #if NAMED_BIND
2053 	_res.retry = saveretry;
2054 #endif /* NAMED_BIND */
2055 
2056 	if (hp != NULL && hp->h_name[0] != '[' &&
2057 	    inet_addr(hp->h_name) == INADDR_NONE)
2058 		return denlstring((char *) hp->h_name, TRUE, TRUE);
2059 #if NETUNIX
2060 	else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
2061 		return "localhost";
2062 #endif
2063 	else
2064 	{
2065 		/* produce a dotted quad */
2066 		static char buf[203];
2067 
2068 		(void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
2069 		return buf;
2070 	}
2071 }
2072 
2073 #endif /* SOCK_STREAM */
2074