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