xref: /illumos-gate/usr/src/cmd/sendmail/src/daemon.c (revision 4aac33d3)
1 /*
2  * Copyright (c) 1998-2007 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13 
14 #pragma ident	"%Z%%M%	%I%	%E% SMI"
15 
16 #include <sendmail.h>
17 #include "map.h"
18 
19 SM_RCSID("@(#)$Id: daemon.c,v 8.678 2007/03/08 00:33:40 ca Exp $")
20 
21 #if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
22 # define USE_SOCK_STREAM	1
23 #endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
24 
25 #if defined(USE_SOCK_STREAM)
26 # if NETINET || NETINET6
27 #  include <arpa/inet.h>
28 # endif /* NETINET || NETINET6 */
29 # if NAMED_BIND
30 #  ifndef NO_DATA
31 #   define NO_DATA	NO_ADDRESS
32 #  endif /* ! NO_DATA */
33 # endif /* NAMED_BIND */
34 #endif /* defined(USE_SOCK_STREAM) */
35 
36 #if STARTTLS
37 #  include <openssl/rand.h>
38 #endif /* STARTTLS */
39 
40 #include <sm/time.h>
41 
42 #if IP_SRCROUTE && NETINET
43 # include <netinet/in_systm.h>
44 # include <netinet/ip.h>
45 # if HAS_IN_H
46 #  include <netinet/in.h>
47 #  ifndef IPOPTION
48 #   define IPOPTION	ip_opts
49 #   define IP_LIST	ip_opts
50 #   define IP_DST	ip_dst
51 #  endif /* ! IPOPTION */
52 # else /* HAS_IN_H */
53 #  include <netinet/ip_var.h>
54 #  ifndef IPOPTION
55 #   define IPOPTION	ipoption
56 #   define IP_LIST	ipopt_list
57 #   define IP_DST	ipopt_dst
58 #  endif /* ! IPOPTION */
59 # endif /* HAS_IN_H */
60 #endif /* IP_SRCROUTE && NETINET */
61 
62 #include <sm/fdset.h>
63 
64 #define DAEMON_C 1
65 #include <daemon.h>
66 
67 static void		connecttimeout __P((int));
68 static int		opendaemonsocket __P((DAEMON_T *, bool));
69 static unsigned short	setupdaemon __P((SOCKADDR *));
70 static void		getrequests_checkdiskspace __P((ENVELOPE *e));
71 static void		setsockaddroptions __P((char *, DAEMON_T *));
72 static void		printdaemonflags __P((DAEMON_T *));
73 static int		addr_family __P((char *));
74 static int		addrcmp __P((struct hostent *, char *, SOCKADDR *));
75 static void		authtimeout __P((int));
76 
77 /*
78 **  DAEMON.C -- routines to use when running as a daemon.
79 **
80 **	This entire file is highly dependent on the 4.2 BSD
81 **	interprocess communication primitives.  No attempt has
82 **	been made to make this file portable to Version 7,
83 **	Version 6, MPX files, etc.  If you should try such a
84 **	thing yourself, I recommend chucking the entire file
85 **	and starting from scratch.  Basic semantics are:
86 **
87 **	getrequests(e)
88 **		Opens a port and initiates a connection.
89 **		Returns in a child.  Must set InChannel and
90 **		OutChannel appropriately.
91 **	clrdaemon()
92 **		Close any open files associated with getting
93 **		the connection; this is used when running the queue,
94 **		etc., to avoid having extra file descriptors during
95 **		the queue run and to avoid confusing the network
96 **		code (if it cares).
97 **	makeconnection(host, port, mci, e, enough)
98 **		Make a connection to the named host on the given
99 **		port. Returns zero on success, else an exit status
100 **		describing the error.
101 **	host_map_lookup(map, hbuf, avp, pstat)
102 **		Convert the entry in hbuf into a canonical form.
103 */
104 
105 static int	NDaemons = 0;			/* actual number of daemons */
106 
107 static time_t	NextDiskSpaceCheck = 0;
108 
109 /*
110 **  GETREQUESTS -- open mail IPC port and get requests.
111 **
112 **	Parameters:
113 **		e -- the current envelope.
114 **
115 **	Returns:
116 **		pointer to flags.
117 **
118 **	Side Effects:
119 **		Waits until some interesting activity occurs.  When
120 **		it does, a child is created to process it, and the
121 **		parent waits for completion.  Return from this
122 **		routine is always in the child.  The file pointers
123 **		"InChannel" and "OutChannel" should be set to point
124 **		to the communication channel.
125 **		May restart persistent queue runners if they have ended
126 **		for some reason.
127 */
128 
129 BITMAP256 *
130 getrequests(e)
131 	ENVELOPE *e;
132 {
133 	int t;
134 	int idx, curdaemon = -1;
135 	int i, olddaemon = 0;
136 #if XDEBUG
137 	bool j_has_dot;
138 #endif /* XDEBUG */
139 	char status[MAXLINE];
140 	SOCKADDR sa;
141 	SOCKADDR_LEN_T len = sizeof(sa);
142 #if _FFR_QUEUE_RUN_PARANOIA
143 	time_t lastrun;
144 #endif /* _FFR_QUEUE_RUN_PARANOIA */
145 # if NETUNIX
146 	extern int ControlSocket;
147 # endif /* NETUNIX */
148 	extern ENVELOPE BlankEnvelope;
149 
150 
151 	/* initialize data for function that generates queue ids */
152 	init_qid_alg();
153 	for (idx = 0; idx < NDaemons; idx++)
154 	{
155 		Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
156 		Daemons[idx].d_firsttime = true;
157 		Daemons[idx].d_refuse_connections_until = (time_t) 0;
158 	}
159 
160 	/*
161 	**  Try to actually open the connection.
162 	*/
163 
164 	if (tTd(15, 1))
165 	{
166 		for (idx = 0; idx < NDaemons; idx++)
167 		{
168 			sm_dprintf("getrequests: daemon %s: port %d\n",
169 				   Daemons[idx].d_name,
170 				   ntohs(Daemons[idx].d_port));
171 		}
172 	}
173 
174 	/* get a socket for the SMTP connection */
175 	for (idx = 0; idx < NDaemons; idx++)
176 		Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true);
177 
178 	if (opencontrolsocket() < 0)
179 		sm_syslog(LOG_WARNING, NOQID,
180 			  "daemon could not open control socket %s: %s",
181 			  ControlSocketName, sm_errstring(errno));
182 
183 	/* If there are any queue runners released reapchild() co-ord's */
184 	(void) sm_signal(SIGCHLD, reapchild);
185 
186 	/* write the pid to file, command line args to syslog */
187 	log_sendmail_pid(e);
188 
189 #if XDEBUG
190 	{
191 		char jbuf[MAXHOSTNAMELEN];
192 
193 		expand("\201j", jbuf, sizeof(jbuf), e);
194 		j_has_dot = strchr(jbuf, '.') != NULL;
195 	}
196 #endif /* XDEBUG */
197 
198 	/* Add parent process as first item */
199 	proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL);
200 
201 	if (tTd(15, 1))
202 	{
203 		for (idx = 0; idx < NDaemons; idx++)
204 			sm_dprintf("getrequests: daemon %s: %d\n",
205 				Daemons[idx].d_name,
206 				Daemons[idx].d_socket);
207 	}
208 
209 	for (;;)
210 	{
211 		register pid_t pid;
212 		auto SOCKADDR_LEN_T lotherend;
213 		bool timedout = false;
214 		bool control = false;
215 		int save_errno;
216 		int pipefd[2];
217 		time_t now;
218 #if STARTTLS
219 		long seed;
220 #endif /* STARTTLS */
221 
222 		/* see if we are rejecting connections */
223 		(void) sm_blocksignal(SIGALRM);
224 		CHECK_RESTART;
225 
226 		for (idx = 0; idx < NDaemons; idx++)
227 		{
228 			/*
229 			**  XXX do this call outside the loop?
230 			**	no: refuse_connections may sleep().
231 			*/
232 
233 			now = curtime();
234 			if (now < Daemons[idx].d_refuse_connections_until)
235 				continue;
236 			if (bitnset(D_DISABLE, Daemons[idx].d_flags))
237 				continue;
238 			if (refuseconnections(e, idx, curdaemon == idx))
239 			{
240 				if (Daemons[idx].d_socket >= 0)
241 				{
242 					/* close socket so peer fails quickly */
243 					(void) close(Daemons[idx].d_socket);
244 					Daemons[idx].d_socket = -1;
245 				}
246 
247 				/* refuse connections for next 15 seconds */
248 				Daemons[idx].d_refuse_connections_until = now + 15;
249 			}
250 			else if (Daemons[idx].d_socket < 0 ||
251 				 Daemons[idx].d_firsttime)
252 			{
253 				if (!Daemons[idx].d_firsttime && LogLevel > 8)
254 					sm_syslog(LOG_INFO, NOQID,
255 						"accepting connections again for daemon %s",
256 						Daemons[idx].d_name);
257 
258 				/* arrange to (re)open the socket if needed */
259 				(void) opendaemonsocket(&Daemons[idx], false);
260 				Daemons[idx].d_firsttime = false;
261 			}
262 		}
263 
264 		/* May have been sleeping above, check again */
265 		CHECK_RESTART;
266 
267 		getrequests_checkdiskspace(e);
268 
269 #if XDEBUG
270 		/* check for disaster */
271 		{
272 			char jbuf[MAXHOSTNAMELEN];
273 
274 			expand("\201j", jbuf, sizeof(jbuf), e);
275 			if (!wordinclass(jbuf, 'w'))
276 			{
277 				dumpstate("daemon lost $j");
278 				sm_syslog(LOG_ALERT, NOQID,
279 					  "daemon process doesn't have $j in $=w; see syslog");
280 				abort();
281 			}
282 			else if (j_has_dot && strchr(jbuf, '.') == NULL)
283 			{
284 				dumpstate("daemon $j lost dot");
285 				sm_syslog(LOG_ALERT, NOQID,
286 					  "daemon process $j lost dot; see syslog");
287 				abort();
288 			}
289 		}
290 #endif /* XDEBUG */
291 
292 #if 0
293 		/*
294 		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
295 		**  fix the SVr4 problem.  But it seems to have gone away,
296 		**  so is it worth doing this?
297 		*/
298 
299 		if (DaemonSocket >= 0 &&
300 		    SetNonBlocking(DaemonSocket, false) < 0)
301 			log an error here;
302 #endif /* 0 */
303 		(void) sm_releasesignal(SIGALRM);
304 
305 		for (;;)
306 		{
307 			bool setproc = false;
308 			int highest = -1;
309 			fd_set readfds;
310 			struct timeval timeout;
311 
312 			CHECK_RESTART;
313 			FD_ZERO(&readfds);
314 			for (idx = 0; idx < NDaemons; idx++)
315 			{
316 				/* wait for a connection */
317 				if (Daemons[idx].d_socket >= 0)
318 				{
319 					if (!setproc &&
320 					    !bitnset(D_ETRNONLY,
321 						     Daemons[idx].d_flags))
322 					{
323 						sm_setproctitle(true, e,
324 								"accepting connections");
325 						setproc = true;
326 					}
327 					if (Daemons[idx].d_socket > highest)
328 						highest = Daemons[idx].d_socket;
329 					SM_FD_SET(Daemons[idx].d_socket,
330 						  &readfds);
331 				}
332 			}
333 
334 #if NETUNIX
335 			if (ControlSocket >= 0)
336 			{
337 				if (ControlSocket > highest)
338 					highest = ControlSocket;
339 				SM_FD_SET(ControlSocket, &readfds);
340 			}
341 #endif /* NETUNIX */
342 
343 			timeout.tv_sec = 5;
344 			timeout.tv_usec = 0;
345 
346 			t = select(highest + 1, FDSET_CAST &readfds,
347 				   NULL, NULL, &timeout);
348 
349 			/* Did someone signal while waiting? */
350 			CHECK_RESTART;
351 
352 			curdaemon = -1;
353 			if (doqueuerun())
354 			{
355 				(void) runqueue(true, false, false, false);
356 #if _FFR_QUEUE_RUN_PARANOIA
357 				lastrun = now;
358 #endif /* _FFR_QUEUE_RUN_PARANOIA */
359 			}
360 #if _FFR_QUEUE_RUN_PARANOIA
361 			else if (CheckQueueRunners > 0 && QueueIntvl > 0 &&
362 				 lastrun + QueueIntvl + CheckQueueRunners < now)
363 			{
364 
365 				/*
366 				**  set lastrun unconditionally to avoid
367 				**  calling checkqueuerunner() all the time.
368 				**  That's also why we currently ignore the
369 				**  result of the function call.
370 				*/
371 
372 				(void) checkqueuerunner();
373 				lastrun = now;
374 			}
375 #endif /* _FFR_QUEUE_RUN_PARANOIA */
376 
377 			if (t <= 0)
378 			{
379 				timedout = true;
380 				break;
381 			}
382 
383 			control = false;
384 			errno = 0;
385 
386 			/* look "round-robin" for an active socket */
387 			if ((idx = olddaemon + 1) >= NDaemons)
388 				idx = 0;
389 			for (i = 0; i < NDaemons; i++)
390 			{
391 				if (Daemons[idx].d_socket >= 0 &&
392 				    SM_FD_ISSET(Daemons[idx].d_socket,
393 						&readfds))
394 				{
395 					lotherend = Daemons[idx].d_socksize;
396 					memset(&RealHostAddr, '\0',
397 					       sizeof(RealHostAddr));
398 					t = accept(Daemons[idx].d_socket,
399 						   (struct sockaddr *)&RealHostAddr,
400 						   &lotherend);
401 
402 					/*
403 					**  If remote side closes before
404 					**  accept() finishes, sockaddr
405 					**  might not be fully filled in.
406 					*/
407 
408 					if (t >= 0 &&
409 					    (lotherend == 0 ||
410 # ifdef BSD4_4_SOCKADDR
411 					     RealHostAddr.sa.sa_len == 0 ||
412 # endif /* BSD4_4_SOCKADDR */
413 					     RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family))
414 					{
415 						(void) close(t);
416 						t = -1;
417 						errno = EINVAL;
418 					}
419 					olddaemon = curdaemon = idx;
420 					break;
421 				}
422 				if (++idx >= NDaemons)
423 					idx = 0;
424 			}
425 #if NETUNIX
426 			if (curdaemon == -1 && ControlSocket >= 0 &&
427 			    SM_FD_ISSET(ControlSocket, &readfds))
428 			{
429 				struct sockaddr_un sa_un;
430 
431 				lotherend = sizeof(sa_un);
432 				memset(&sa_un, '\0', sizeof(sa_un));
433 				t = accept(ControlSocket,
434 					   (struct sockaddr *)&sa_un,
435 					   &lotherend);
436 
437 				/*
438 				**  If remote side closes before
439 				**  accept() finishes, sockaddr
440 				**  might not be fully filled in.
441 				*/
442 
443 				if (t >= 0 &&
444 				    (lotherend == 0 ||
445 # ifdef BSD4_4_SOCKADDR
446 				     sa_un.sun_len == 0 ||
447 # endif /* BSD4_4_SOCKADDR */
448 				     sa_un.sun_family != AF_UNIX))
449 				{
450 					(void) close(t);
451 					t = -1;
452 					errno = EINVAL;
453 				}
454 				if (t >= 0)
455 					control = true;
456 			}
457 #else /* NETUNIX */
458 			if (curdaemon == -1)
459 			{
460 				/* No daemon to service */
461 				continue;
462 			}
463 #endif /* NETUNIX */
464 			if (t >= 0 || errno != EINTR)
465 				break;
466 		}
467 		if (timedout)
468 		{
469 			timedout = false;
470 			continue;
471 		}
472 		save_errno = errno;
473 		(void) sm_blocksignal(SIGALRM);
474 		if (t < 0)
475 		{
476 			errno = save_errno;
477 
478 			/* let's ignore these temporary errors */
479 			if (save_errno == EINTR
480 #ifdef EAGAIN
481 			    || save_errno == EAGAIN
482 #endif /* EAGAIN */
483 #ifdef ECONNABORTED
484 			    || save_errno == ECONNABORTED
485 #endif /* ECONNABORTED */
486 #ifdef EWOULDBLOCK
487 			    || save_errno == EWOULDBLOCK
488 #endif /* EWOULDBLOCK */
489 			   )
490 				continue;
491 
492 			syserr("getrequests: accept");
493 
494 			if (curdaemon >= 0)
495 			{
496 				/* arrange to re-open socket next time around */
497 				(void) close(Daemons[curdaemon].d_socket);
498 				Daemons[curdaemon].d_socket = -1;
499 #if SO_REUSEADDR_IS_BROKEN
500 				/*
501 				**  Give time for bound socket to be released.
502 				**  This creates a denial-of-service if you can
503 				**  force accept() to fail on affected systems.
504 				*/
505 
506 				Daemons[curdaemon].d_refuse_connections_until =
507 					curtime() + 15;
508 #endif /* SO_REUSEADDR_IS_BROKEN */
509 			}
510 			continue;
511 		}
512 
513 		if (!control)
514 		{
515 			/* set some daemon related macros */
516 			switch (Daemons[curdaemon].d_addr.sa.sa_family)
517 			{
518 			  case AF_UNSPEC:
519 				macdefine(&BlankEnvelope.e_macro, A_PERM,
520 					macid("{daemon_family}"), "unspec");
521 				break;
522 #if _FFR_DAEMON_NETUNIX
523 # if NETUNIX
524 			  case AF_UNIX:
525 				macdefine(&BlankEnvelope.e_macro, A_PERM,
526 					macid("{daemon_family}"), "local");
527 				break;
528 # endif /* NETUNIX */
529 #endif /* _FFR_DAEMON_NETUNIX */
530 #if NETINET
531 			  case AF_INET:
532 				macdefine(&BlankEnvelope.e_macro, A_PERM,
533 					macid("{daemon_family}"), "inet");
534 				break;
535 #endif /* NETINET */
536 #if NETINET6
537 			  case AF_INET6:
538 				macdefine(&BlankEnvelope.e_macro, A_PERM,
539 					macid("{daemon_family}"), "inet6");
540 				break;
541 #endif /* NETINET6 */
542 #if NETISO
543 			  case AF_ISO:
544 				macdefine(&BlankEnvelope.e_macro, A_PERM,
545 					macid("{daemon_family}"), "iso");
546 				break;
547 #endif /* NETISO */
548 #if NETNS
549 			  case AF_NS:
550 				macdefine(&BlankEnvelope.e_macro, A_PERM,
551 					macid("{daemon_family}"), "ns");
552 				break;
553 #endif /* NETNS */
554 #if NETX25
555 			  case AF_CCITT:
556 				macdefine(&BlankEnvelope.e_macro, A_PERM,
557 					macid("{daemon_family}"), "x.25");
558 				break;
559 #endif /* NETX25 */
560 			}
561 			macdefine(&BlankEnvelope.e_macro, A_PERM,
562 				macid("{daemon_name}"),
563 				Daemons[curdaemon].d_name);
564 			if (Daemons[curdaemon].d_mflags != NULL)
565 				macdefine(&BlankEnvelope.e_macro, A_PERM,
566 					macid("{daemon_flags}"),
567 					Daemons[curdaemon].d_mflags);
568 			else
569 				macdefine(&BlankEnvelope.e_macro, A_PERM,
570 					macid("{daemon_flags}"), "");
571 		}
572 
573 		/*
574 		**  If connection rate is exceeded here, connection shall be
575 		**  refused later by a new call after fork() by the
576 		**  validate_connection() function. Closing the connection
577 		**  at this point violates RFC 2821.
578 		**  Do NOT remove this call, its side effects are needed.
579 		*/
580 
581 		connection_rate_check(&RealHostAddr, NULL);
582 
583 		/*
584 		**  Create a subprocess to process the mail.
585 		*/
586 
587 		if (tTd(15, 2))
588 			sm_dprintf("getrequests: forking (fd = %d)\n", t);
589 
590 		/*
591 		**  Advance state of PRNG.
592 		**  This is necessary because otherwise all child processes
593 		**  will produce the same PRN sequence and hence the selection
594 		**  of a queue directory (and other things, e.g., MX selection)
595 		**  are not "really" random.
596 		*/
597 #if STARTTLS
598 		/* XXX get some better "random" data? */
599 		seed = get_random();
600 		RAND_seed((void *) &NextDiskSpaceCheck,
601 			  sizeof(NextDiskSpaceCheck));
602 		RAND_seed((void *) &now, sizeof(now));
603 		RAND_seed((void *) &seed, sizeof(seed));
604 #else /* STARTTLS */
605 		(void) get_random();
606 #endif /* STARTTLS */
607 
608 #if NAMED_BIND
609 		/*
610 		**  Update MX records for FallbackMX.
611 		**  Let's hope this is fast otherwise we screw up the
612 		**  response time.
613 		*/
614 
615 		if (FallbackMX != NULL)
616 			(void) getfallbackmxrr(FallbackMX);
617 #endif /* NAMED_BIND */
618 
619 		if (tTd(93, 100))
620 		{
621 			/* don't fork, handle connection in this process */
622 			pid = 0;
623 			pipefd[0] = pipefd[1] = -1;
624 		}
625 		else
626 		{
627 			/*
628 			**  Create a pipe to keep the child from writing to
629 			**  the socket until after the parent has closed
630 			**  it.  Otherwise the parent may hang if the child
631 			**  has closed it first.
632 			*/
633 
634 			if (pipe(pipefd) < 0)
635 				pipefd[0] = pipefd[1] = -1;
636 
637 			(void) sm_blocksignal(SIGCHLD);
638 			pid = fork();
639 			if (pid < 0)
640 			{
641 				syserr("daemon: cannot fork");
642 				if (pipefd[0] != -1)
643 				{
644 					(void) close(pipefd[0]);
645 					(void) close(pipefd[1]);
646 				}
647 				(void) sm_releasesignal(SIGCHLD);
648 				(void) sleep(10);
649 				(void) close(t);
650 				continue;
651 			}
652 		}
653 
654 		if (pid == 0)
655 		{
656 			char *p;
657 			SM_FILE_T *inchannel, *outchannel = NULL;
658 
659 			/*
660 			**  CHILD -- return to caller.
661 			**	Collect verified idea of sending host.
662 			**	Verify calling user id if possible here.
663 			*/
664 
665 			/* Reset global flags */
666 			RestartRequest = NULL;
667 			RestartWorkGroup = false;
668 			ShutdownRequest = NULL;
669 			PendingSignal = 0;
670 			CurrentPid = getpid();
671 			close_sendmail_pid();
672 
673 			(void) sm_releasesignal(SIGALRM);
674 			(void) sm_releasesignal(SIGCHLD);
675 			(void) sm_signal(SIGCHLD, SIG_DFL);
676 			(void) sm_signal(SIGHUP, SIG_DFL);
677 			(void) sm_signal(SIGTERM, intsig);
678 
679 			/* turn on profiling */
680 			/* SM_PROF(0); */
681 
682 			/*
683 			**  Initialize exception stack and default exception
684 			**  handler for child process.
685 			*/
686 
687 			sm_exc_newthread(fatal_error);
688 
689 			if (!control)
690 			{
691 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
692 					macid("{daemon_addr}"),
693 					anynet_ntoa(&Daemons[curdaemon].d_addr));
694 				(void) sm_snprintf(status, sizeof(status), "%d",
695 						ntohs(Daemons[curdaemon].d_port));
696 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
697 					macid("{daemon_port}"), status);
698 			}
699 
700 			for (idx = 0; idx < NDaemons; idx++)
701 			{
702 				if (Daemons[idx].d_socket >= 0)
703 					(void) close(Daemons[idx].d_socket);
704 				Daemons[idx].d_socket = -1;
705 			}
706 			clrcontrol();
707 
708 			/* Avoid SMTP daemon actions if control command */
709 			if (control)
710 			{
711 				/* Add control socket process */
712 				proc_list_add(CurrentPid,
713 					      "console socket child",
714 					      PROC_CONTROL_CHILD, 0, -1, NULL);
715 			}
716 			else
717 			{
718 				proc_list_clear();
719 
720 				/* clean up background delivery children */
721 				(void) sm_signal(SIGCHLD, reapchild);
722 
723 				/* Add parent process as first child item */
724 				proc_list_add(CurrentPid, "daemon child",
725 					      PROC_DAEMON_CHILD, 0, -1, NULL);
726 				/* don't schedule queue runs if ETRN */
727 				QueueIntvl = 0;
728 
729 				/*
730 				**  Hack: override global variables if
731 				**	the corresponding DaemonPortOption
732 				**	is set.
733 				*/
734 #if _FFR_SS_PER_DAEMON
735 				if (Daemons[curdaemon].d_supersafe !=
736 				    DPO_NOTSET)
737 					SuperSafe = Daemons[curdaemon].
738 								d_supersafe;
739 #endif /* _FFR_SS_PER_DAEMON */
740 				if (Daemons[curdaemon].d_dm != DM_NOTSET)
741 					set_delivery_mode(
742 						Daemons[curdaemon].d_dm, e);
743 
744 				if (Daemons[curdaemon].d_refuseLA !=
745 				    DPO_NOTSET)
746 					RefuseLA = Daemons[curdaemon].
747 								d_refuseLA;
748 				if (Daemons[curdaemon].d_queueLA != DPO_NOTSET)
749 					QueueLA = Daemons[curdaemon].d_queueLA;
750 				if (Daemons[curdaemon].d_delayLA != DPO_NOTSET)
751 					DelayLA = Daemons[curdaemon].d_delayLA;
752 				if (Daemons[curdaemon].d_maxchildren !=
753 				    DPO_NOTSET)
754 					MaxChildren = Daemons[curdaemon].
755 								d_maxchildren;
756 
757 				sm_setproctitle(true, e, "startup with %s",
758 						anynet_ntoa(&RealHostAddr));
759 			}
760 
761 			if (pipefd[0] != -1)
762 			{
763 				auto char c;
764 
765 				/*
766 				**  Wait for the parent to close the write end
767 				**  of the pipe, which we will see as an EOF.
768 				**  This guarantees that we won't write to the
769 				**  socket until after the parent has closed
770 				**  the pipe.
771 				*/
772 
773 				/* close the write end of the pipe */
774 				(void) close(pipefd[1]);
775 
776 				/* we shouldn't be interrupted, but ... */
777 				while (read(pipefd[0], &c, 1) < 0 &&
778 				       errno == EINTR)
779 					continue;
780 				(void) close(pipefd[0]);
781 			}
782 
783 			/* control socket processing */
784 			if (control)
785 			{
786 				control_command(t, e);
787 				/* NOTREACHED */
788 				exit(EX_SOFTWARE);
789 			}
790 
791 			/* determine host name */
792 			p = hostnamebyanyaddr(&RealHostAddr);
793 			if (strlen(p) > MAXNAME) /* XXX  - 1 ? */
794 				p[MAXNAME] = '\0';
795 			RealHostName = newstr(p);
796 			if (RealHostName[0] == '[')
797 			{
798 				macdefine(&BlankEnvelope.e_macro, A_PERM,
799 					macid("{client_resolve}"),
800 					h_errno == TRY_AGAIN ? "TEMP" : "FAIL");
801 			}
802 			else
803 			{
804 				macdefine(&BlankEnvelope.e_macro, A_PERM,
805 					  macid("{client_resolve}"), "OK");
806 			}
807 			sm_setproctitle(true, e, "startup with %s", p);
808 			markstats(e, NULL, STATS_CONNECT);
809 
810 			if ((inchannel = sm_io_open(SmFtStdiofd,
811 						    SM_TIME_DEFAULT,
812 						    (void *) &t,
813 						    SM_IO_RDONLY_B,
814 						    NULL)) == NULL ||
815 			    (t = dup(t)) < 0 ||
816 			    (outchannel = sm_io_open(SmFtStdiofd,
817 						     SM_TIME_DEFAULT,
818 						     (void *) &t,
819 						     SM_IO_WRONLY_B,
820 						     NULL)) == NULL)
821 			{
822 				syserr("cannot open SMTP server channel, fd=%d",
823 					t);
824 				finis(false, true, EX_OK);
825 			}
826 			sm_io_automode(inchannel, outchannel);
827 
828 			InChannel = inchannel;
829 			OutChannel = outchannel;
830 			DisConnected = false;
831 
832 #if XLA
833 			if (!xla_host_ok(RealHostName))
834 			{
835 				message("421 4.4.5 Too many SMTP sessions for this host");
836 				finis(false, true, EX_OK);
837 			}
838 #endif /* XLA */
839 			/* find out name for interface of connection */
840 			if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
841 						      NULL), &sa.sa, &len) == 0)
842 			{
843 				p = hostnamebyanyaddr(&sa);
844 				if (tTd(15, 9))
845 					sm_dprintf("getreq: got name %s\n", p);
846 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
847 					macid("{if_name}"), p);
848 
849 				/*
850 				**  Do this only if it is not the loopback
851 				**  interface.
852 				*/
853 
854 				if (!isloopback(sa))
855 				{
856 					char *addr;
857 					char family[5];
858 
859 					addr = anynet_ntoa(&sa);
860 					(void) sm_snprintf(family,
861 						sizeof(family),
862 						"%d", sa.sa.sa_family);
863 					macdefine(&BlankEnvelope.e_macro,
864 						A_TEMP,
865 						macid("{if_addr}"), addr);
866 					macdefine(&BlankEnvelope.e_macro,
867 						A_TEMP,
868 						macid("{if_family}"), family);
869 					if (tTd(15, 7))
870 						sm_dprintf("getreq: got addr %s and family %s\n",
871 							addr, family);
872 				}
873 				else
874 				{
875 					macdefine(&BlankEnvelope.e_macro,
876 						A_PERM,
877 						macid("{if_addr}"), NULL);
878 					macdefine(&BlankEnvelope.e_macro,
879 						A_PERM,
880 						macid("{if_family}"), NULL);
881 				}
882 			}
883 			else
884 			{
885 				if (tTd(15, 7))
886 					sm_dprintf("getreq: getsockname failed\n");
887 				macdefine(&BlankEnvelope.e_macro, A_PERM,
888 					macid("{if_name}"), NULL);
889 				macdefine(&BlankEnvelope.e_macro, A_PERM,
890 					macid("{if_addr}"), NULL);
891 				macdefine(&BlankEnvelope.e_macro, A_PERM,
892 					macid("{if_family}"), NULL);
893 			}
894 			break;
895 		}
896 
897 		/* parent -- keep track of children */
898 		if (control)
899 		{
900 			(void) sm_snprintf(status, sizeof(status),
901 					   "control socket server child");
902 			proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL);
903 		}
904 		else
905 		{
906 			(void) sm_snprintf(status, sizeof(status),
907 					   "SMTP server child for %s",
908 					   anynet_ntoa(&RealHostAddr));
909 			proc_list_add(pid, status, PROC_DAEMON, 0, -1,
910 					&RealHostAddr);
911 		}
912 		(void) sm_releasesignal(SIGCHLD);
913 
914 		/* close the read end of the synchronization pipe */
915 		if (pipefd[0] != -1)
916 		{
917 			(void) close(pipefd[0]);
918 			pipefd[0] = -1;
919 		}
920 
921 		/* close the port so that others will hang (for a while) */
922 		(void) close(t);
923 
924 		/* release the child by closing the read end of the sync pipe */
925 		if (pipefd[1] != -1)
926 		{
927 			(void) close(pipefd[1]);
928 			pipefd[1] = -1;
929 		}
930 	}
931 	if (tTd(15, 2))
932 		sm_dprintf("getreq: returning\n");
933 
934 #if MILTER
935 	/* set the filters for this daemon */
936 	if (Daemons[curdaemon].d_inputfilterlist != NULL)
937 	{
938 		for (i = 0;
939 		     (i < MAXFILTERS &&
940 		      Daemons[curdaemon].d_inputfilters[i] != NULL);
941 		     i++)
942 		{
943 			InputFilters[i] = Daemons[curdaemon].d_inputfilters[i];
944 		}
945 		if (i < MAXFILTERS)
946 			InputFilters[i] = NULL;
947 	}
948 #endif /* MILTER */
949 	return &Daemons[curdaemon].d_flags;
950 }
951 
952 /*
953 **  GETREQUESTS_CHECKDISKSPACE -- check available diskspace.
954 **
955 **	Parameters:
956 **		e -- envelope.
957 **
958 **	Returns:
959 **		none.
960 **
961 **	Side Effects:
962 **		Modifies Daemon flags (D_ETRNONLY) if not enough disk space.
963 */
964 
965 static void
966 getrequests_checkdiskspace(e)
967 	ENVELOPE *e;
968 {
969 	bool logged = false;
970 	int idx;
971 	time_t now;
972 
973 	now = curtime();
974 	if (now < NextDiskSpaceCheck)
975 		return;
976 
977 	/* Check if there is available disk space in all queue groups. */
978 	if (!enoughdiskspace(0, NULL))
979 	{
980 		for (idx = 0; idx < NDaemons; ++idx)
981 		{
982 			if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
983 				continue;
984 
985 			/* log only if not logged before */
986 			if (!logged)
987 			{
988 				if (LogLevel > 8)
989 					sm_syslog(LOG_INFO, NOQID,
990 						  "rejecting new messages: min free: %ld",
991 						  MinBlocksFree);
992 				sm_setproctitle(true, e,
993 						"rejecting new messages: min free: %ld",
994 						MinBlocksFree);
995 				logged = true;
996 			}
997 			setbitn(D_ETRNONLY, Daemons[idx].d_flags);
998 		}
999 	}
1000 	else
1001 	{
1002 		for (idx = 0; idx < NDaemons; ++idx)
1003 		{
1004 			if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
1005 				continue;
1006 
1007 			/* log only if not logged before */
1008 			if (!logged)
1009 			{
1010 				if (LogLevel > 8)
1011 					sm_syslog(LOG_INFO, NOQID,
1012 						  "accepting new messages (again)");
1013 				logged = true;
1014 			}
1015 
1016 			/* title will be set later */
1017 			clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
1018 		}
1019 	}
1020 
1021 	/* only check disk space once a minute */
1022 	NextDiskSpaceCheck = now + 60;
1023 }
1024 
1025 /*
1026 **  OPENDAEMONSOCKET -- open SMTP socket
1027 **
1028 **	Deals with setting all appropriate options.
1029 **
1030 **	Parameters:
1031 **		d -- the structure for the daemon to open.
1032 **		firsttime -- set if this is the initial open.
1033 **
1034 **	Returns:
1035 **		Size in bytes of the daemon socket addr.
1036 **
1037 **	Side Effects:
1038 **		Leaves DaemonSocket set to the open socket.
1039 **		Exits if the socket cannot be created.
1040 */
1041 
1042 #define MAXOPENTRIES	10	/* maximum number of tries to open connection */
1043 
1044 static int
1045 opendaemonsocket(d, firsttime)
1046 	DAEMON_T *d;
1047 	bool firsttime;
1048 {
1049 	int on = 1;
1050 	int fdflags;
1051 	SOCKADDR_LEN_T socksize = 0;
1052 	int ntries = 0;
1053 	int save_errno;
1054 
1055 	if (tTd(15, 2))
1056 		sm_dprintf("opendaemonsocket(%s)\n", d->d_name);
1057 
1058 	do
1059 	{
1060 		if (ntries > 0)
1061 			(void) sleep(5);
1062 		if (firsttime || d->d_socket < 0)
1063 		{
1064 #if _FFR_DAEMON_NETUNIX
1065 # if NETUNIX
1066 			if (d->d_addr.sa.sa_family == AF_UNIX)
1067 			{
1068 				int rval;
1069 				long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT;
1070 
1071 				/* if not safe, don't use it */
1072 				rval = safefile(d->d_addr.sunix.sun_path,
1073 						RunAsUid, RunAsGid,
1074 						RunAsUserName, sff,
1075 						S_IRUSR|S_IWUSR, NULL);
1076 				if (rval != 0)
1077 				{
1078 					save_errno = errno;
1079 					syserr("opendaemonsocket: daemon %s: unsafe domain socket %s",
1080 					       d->d_name,
1081 					       d->d_addr.sunix.sun_path);
1082 					goto fail;
1083 				}
1084 
1085 				/* Don't try to overtake an existing socket */
1086 				(void) unlink(d->d_addr.sunix.sun_path);
1087 			}
1088 # endif /* NETUNIX */
1089 #endif /* _FFR_DOMAIN_NETUNIX */
1090 			d->d_socket = socket(d->d_addr.sa.sa_family,
1091 					     SOCK_STREAM, 0);
1092 			if (d->d_socket < 0)
1093 			{
1094 				save_errno = errno;
1095 				syserr("opendaemonsocket: daemon %s: can't create server SMTP socket",
1096 				       d->d_name);
1097 			  fail:
1098 				if (bitnset(D_OPTIONAL, d->d_flags) &&
1099 				    (!transienterror(save_errno) ||
1100 				     ntries >= MAXOPENTRIES - 1))
1101 				{
1102 					syserr("opendaemonsocket: daemon %s: optional socket disabled",
1103 					       d->d_name);
1104 					setbitn(D_DISABLE, d->d_flags);
1105 					d->d_socket = -1;
1106 					return -1;
1107 				}
1108 			  severe:
1109 				if (LogLevel > 0)
1110 					sm_syslog(LOG_ALERT, NOQID,
1111 						  "daemon %s: problem creating SMTP socket",
1112 						  d->d_name);
1113 				d->d_socket = -1;
1114 				continue;
1115 			}
1116 
1117 			if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE)
1118 			{
1119 				save_errno = EINVAL;
1120 				syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large",
1121 				       d->d_name, d->d_socket);
1122 				goto fail;
1123 			}
1124 
1125 			/* turn on network debugging? */
1126 			if (tTd(15, 101))
1127 				(void) setsockopt(d->d_socket, SOL_SOCKET,
1128 						  SO_DEBUG, (char *)&on,
1129 						  sizeof(on));
1130 
1131 			(void) setsockopt(d->d_socket, SOL_SOCKET,
1132 					  SO_REUSEADDR, (char *)&on, sizeof(on));
1133 			(void) setsockopt(d->d_socket, SOL_SOCKET,
1134 					  SO_KEEPALIVE, (char *)&on, sizeof(on));
1135 
1136 #ifdef SO_RCVBUF
1137 			if (d->d_tcprcvbufsize > 0)
1138 			{
1139 				if (setsockopt(d->d_socket, SOL_SOCKET,
1140 					       SO_RCVBUF,
1141 					       (char *) &d->d_tcprcvbufsize,
1142 					       sizeof(d->d_tcprcvbufsize)) < 0)
1143 					syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
1144 			}
1145 #endif /* SO_RCVBUF */
1146 #ifdef SO_SNDBUF
1147 			if (d->d_tcpsndbufsize > 0)
1148 			{
1149 				if (setsockopt(d->d_socket, SOL_SOCKET,
1150 					       SO_SNDBUF,
1151 					       (char *) &d->d_tcpsndbufsize,
1152 					       sizeof(d->d_tcpsndbufsize)) < 0)
1153 					syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
1154 			}
1155 #endif /* SO_SNDBUF */
1156 
1157 			if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
1158 			    fcntl(d->d_socket, F_SETFD,
1159 				  fdflags | FD_CLOEXEC) == -1)
1160 			{
1161 				save_errno = errno;
1162 				syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
1163 				       d->d_name,
1164 				       fdflags == -1 ? "get" : "set",
1165 				       sm_errstring(save_errno));
1166 				(void) close(d->d_socket);
1167 				goto severe;
1168 			}
1169 
1170 			switch (d->d_addr.sa.sa_family)
1171 			{
1172 #if _FFR_DAEMON_NETUNIX
1173 # ifdef NETUNIX
1174 			  case AF_UNIX:
1175 				socksize = sizeof(d->d_addr.sunix);
1176 				break;
1177 # endif /* NETUNIX */
1178 #endif /* _FFR_DAEMON_NETUNIX */
1179 #if NETINET
1180 			  case AF_INET:
1181 				socksize = sizeof(d->d_addr.sin);
1182 				break;
1183 #endif /* NETINET */
1184 
1185 #if NETINET6
1186 			  case AF_INET6:
1187 				socksize = sizeof(d->d_addr.sin6);
1188 				break;
1189 #endif /* NETINET6 */
1190 
1191 #if NETISO
1192 			  case AF_ISO:
1193 				socksize = sizeof(d->d_addr.siso);
1194 				break;
1195 #endif /* NETISO */
1196 
1197 			  default:
1198 				socksize = sizeof(d->d_addr);
1199 				break;
1200 			}
1201 
1202 			if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
1203 			{
1204 				/* probably another daemon already */
1205 				save_errno = errno;
1206 				syserr("opendaemonsocket: daemon %s: cannot bind",
1207 				       d->d_name);
1208 				(void) close(d->d_socket);
1209 				goto fail;
1210 			}
1211 		}
1212 		if (!firsttime &&
1213 		    listen(d->d_socket, d->d_listenqueue) < 0)
1214 		{
1215 			save_errno = errno;
1216 			syserr("opendaemonsocket: daemon %s: cannot listen",
1217 			       d->d_name);
1218 			(void) close(d->d_socket);
1219 			goto severe;
1220 		}
1221 		return socksize;
1222 	} while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
1223 	syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
1224 	       d->d_name);
1225 	/* NOTREACHED */
1226 	return -1;  /* avoid compiler warning on IRIX */
1227 }
1228 /*
1229 **  SETUPDAEMON -- setup socket for daemon
1230 **
1231 **	Parameters:
1232 **		daemonaddr -- socket for daemon
1233 **
1234 **	Returns:
1235 **		port number on which daemon should run
1236 **
1237 */
1238 
1239 static unsigned short
1240 setupdaemon(daemonaddr)
1241 	SOCKADDR *daemonaddr;
1242 {
1243 	unsigned short port;
1244 
1245 	/*
1246 	**  Set up the address for the mailer.
1247 	*/
1248 
1249 	if (daemonaddr->sa.sa_family == AF_UNSPEC)
1250 	{
1251 		memset(daemonaddr, '\0', sizeof(*daemonaddr));
1252 #if NETINET
1253 		daemonaddr->sa.sa_family = AF_INET;
1254 #endif /* NETINET */
1255 	}
1256 
1257 	switch (daemonaddr->sa.sa_family)
1258 	{
1259 #if NETINET
1260 	  case AF_INET:
1261 		if (daemonaddr->sin.sin_addr.s_addr == 0)
1262 			daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
1263 		port = daemonaddr->sin.sin_port;
1264 		break;
1265 #endif /* NETINET */
1266 
1267 #if NETINET6
1268 	  case AF_INET6:
1269 		if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
1270 			daemonaddr->sin6.sin6_addr = in6addr_any;
1271 		port = daemonaddr->sin6.sin6_port;
1272 		break;
1273 #endif /* NETINET6 */
1274 
1275 	  default:
1276 		/* unknown protocol */
1277 		port = 0;
1278 		break;
1279 	}
1280 	if (port == 0)
1281 	{
1282 #ifdef NO_GETSERVBYNAME
1283 		port = htons(25);
1284 #else /* NO_GETSERVBYNAME */
1285 		{
1286 			register struct servent *sp;
1287 
1288 			sp = getservbyname("smtp", "tcp");
1289 			if (sp == NULL)
1290 			{
1291 				syserr("554 5.3.5 service \"smtp\" unknown");
1292 				port = htons(25);
1293 			}
1294 			else
1295 				port = sp->s_port;
1296 		}
1297 #endif /* NO_GETSERVBYNAME */
1298 	}
1299 
1300 	switch (daemonaddr->sa.sa_family)
1301 	{
1302 #if NETINET
1303 	  case AF_INET:
1304 		daemonaddr->sin.sin_port = port;
1305 		break;
1306 #endif /* NETINET */
1307 
1308 #if NETINET6
1309 	  case AF_INET6:
1310 		daemonaddr->sin6.sin6_port = port;
1311 		break;
1312 #endif /* NETINET6 */
1313 
1314 	  default:
1315 		/* unknown protocol */
1316 		break;
1317 	}
1318 	return port;
1319 }
1320 /*
1321 **  CLRDAEMON -- reset the daemon connection
1322 **
1323 **	Parameters:
1324 **		none.
1325 **
1326 **	Returns:
1327 **		none.
1328 **
1329 **	Side Effects:
1330 **		releases any resources used by the passive daemon.
1331 */
1332 
1333 void
1334 clrdaemon()
1335 {
1336 	int i;
1337 
1338 	for (i = 0; i < NDaemons; i++)
1339 	{
1340 		if (Daemons[i].d_socket >= 0)
1341 			(void) close(Daemons[i].d_socket);
1342 		Daemons[i].d_socket = -1;
1343 	}
1344 }
1345 
1346 /*
1347 **  GETMODIFIERS -- get modifier flags
1348 **
1349 **	Parameters:
1350 **		v -- the modifiers (input text line).
1351 **		modifiers -- pointer to flag field to represent modifiers.
1352 **
1353 **	Returns:
1354 **		(xallocat()ed) string representation of modifiers.
1355 **
1356 **	Side Effects:
1357 **		fills in modifiers.
1358 */
1359 
1360 char *
1361 getmodifiers(v, modifiers)
1362 	char *v;
1363 	BITMAP256 modifiers;
1364 {
1365 	int l;
1366 	char *h, *f, *flags;
1367 
1368 	/* maximum length of flags: upper case Option -> "OO " */
1369 	l = 3 * strlen(v) + 3;
1370 
1371 	/* is someone joking? */
1372 	if (l < 0 || l > 256)
1373 	{
1374 		if (LogLevel > 2)
1375 			sm_syslog(LOG_ERR, NOQID,
1376 				  "getmodifiers too long, ignored");
1377 		return NULL;
1378 	}
1379 	flags = xalloc(l);
1380 	f = flags;
1381 	clrbitmap(modifiers);
1382 	for (h = v; *h != '\0'; h++)
1383 	{
1384 		if (isascii(*h) && !isspace(*h) && isprint(*h))
1385 		{
1386 			setbitn(*h, modifiers);
1387 			if (flags != f)
1388 				*flags++ = ' ';
1389 			*flags++ = *h;
1390 			if (isupper(*h))
1391 				*flags++ = *h;
1392 		}
1393 	}
1394 	*flags++ = '\0';
1395 	return f;
1396 }
1397 
1398 /*
1399 **  CHKDAEMONMODIFIERS -- check whether all daemons have set a flag.
1400 **
1401 **	Parameters:
1402 **		flag -- the flag to test.
1403 **
1404 **	Returns:
1405 **		true iff all daemons have set flag.
1406 */
1407 
1408 bool
1409 chkdaemonmodifiers(flag)
1410 	int flag;
1411 {
1412 	int i;
1413 
1414 	for (i = 0; i < NDaemons; i++)
1415 		if (!bitnset((char) flag, Daemons[i].d_flags))
1416 			return false;
1417 	return true;
1418 }
1419 
1420 /*
1421 **  SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
1422 **
1423 **	Parameters:
1424 **		p -- the options line.
1425 **		d -- the daemon structure to fill in.
1426 **
1427 **	Returns:
1428 **		none.
1429 */
1430 
1431 static void
1432 setsockaddroptions(p, d)
1433 	char *p;
1434 	DAEMON_T *d;
1435 {
1436 #if NETISO
1437 	short portno;
1438 #endif /* NETISO */
1439 	char *port = NULL;
1440 	char *addr = NULL;
1441 
1442 #if NETINET
1443 	if (d->d_addr.sa.sa_family == AF_UNSPEC)
1444 		d->d_addr.sa.sa_family = AF_INET;
1445 #endif /* NETINET */
1446 #if _FFR_SS_PER_DAEMON
1447 	d->d_supersafe = DPO_NOTSET;
1448 #endif /* _FFR_SS_PER_DAEMON */
1449 	d->d_dm = DM_NOTSET;
1450 	d->d_refuseLA = DPO_NOTSET;
1451 	d->d_queueLA = DPO_NOTSET;
1452 	d->d_delayLA = DPO_NOTSET;
1453 	d->d_maxchildren = DPO_NOTSET;
1454 
1455 	while (p != NULL)
1456 	{
1457 		register char *f;
1458 		register char *v;
1459 
1460 		while (isascii(*p) && isspace(*p))
1461 			p++;
1462 		if (*p == '\0')
1463 			break;
1464 		f = p;
1465 		p = strchr(p, ',');
1466 		if (p != NULL)
1467 			*p++ = '\0';
1468 		v = strchr(f, '=');
1469 		if (v == NULL)
1470 			continue;
1471 		while (isascii(*++v) && isspace(*v))
1472 			continue;
1473 
1474 		switch (*f)
1475 		{
1476 		  case 'A':		/* address */
1477 #if !_FFR_DPO_CS
1478 		  case 'a':
1479 #endif /* !_FFR_DPO_CS */
1480 			addr = v;
1481 			break;
1482 
1483 		  case 'c':
1484 			d->d_maxchildren = atoi(v);
1485 			break;
1486 
1487 		  case 'D':		/* DeliveryMode */
1488 			switch (*v)
1489 			{
1490 			  case SM_QUEUE:
1491 			  case SM_DEFER:
1492 			  case SM_DELIVER:
1493 			  case SM_FORK:
1494 				d->d_dm = *v;
1495 				break;
1496 			  default:
1497 				syserr("554 5.3.5 Unknown delivery mode %c",
1498 					*v);
1499 				break;
1500 			}
1501 			break;
1502 
1503 		  case 'd':		/* delayLA */
1504 			d->d_delayLA = atoi(v);
1505 			break;
1506 
1507 		  case 'F':		/* address family */
1508 #if !_FFR_DPO_CS
1509 		  case 'f':
1510 #endif /* !_FFR_DPO_CS */
1511 			if (isascii(*v) && isdigit(*v))
1512 				d->d_addr.sa.sa_family = atoi(v);
1513 #if _FFR_DAEMON_NETUNIX
1514 # ifdef NETUNIX
1515 			else if (sm_strcasecmp(v, "unix") == 0 ||
1516 				 sm_strcasecmp(v, "local") == 0)
1517 				d->d_addr.sa.sa_family = AF_UNIX;
1518 # endif /* NETUNIX */
1519 #endif /* _FFR_DAEMON_NETUNIX */
1520 #if NETINET
1521 			else if (sm_strcasecmp(v, "inet") == 0)
1522 				d->d_addr.sa.sa_family = AF_INET;
1523 #endif /* NETINET */
1524 #if NETINET6
1525 			else if (sm_strcasecmp(v, "inet6") == 0)
1526 				d->d_addr.sa.sa_family = AF_INET6;
1527 #endif /* NETINET6 */
1528 #if NETISO
1529 			else if (sm_strcasecmp(v, "iso") == 0)
1530 				d->d_addr.sa.sa_family = AF_ISO;
1531 #endif /* NETISO */
1532 #if NETNS
1533 			else if (sm_strcasecmp(v, "ns") == 0)
1534 				d->d_addr.sa.sa_family = AF_NS;
1535 #endif /* NETNS */
1536 #if NETX25
1537 			else if (sm_strcasecmp(v, "x.25") == 0)
1538 				d->d_addr.sa.sa_family = AF_CCITT;
1539 #endif /* NETX25 */
1540 			else
1541 				syserr("554 5.3.5 Unknown address family %s in Family=option",
1542 				       v);
1543 			break;
1544 
1545 #if MILTER
1546 		  case 'I':
1547 # if !_FFR_DPO_CS
1548 		  case 'i':
1549 # endif /* !_FFR_DPO_CS */
1550 			d->d_inputfilterlist = v;
1551 			break;
1552 #endif /* MILTER */
1553 
1554 		  case 'L':		/* listen queue size */
1555 #if !_FFR_DPO_CS
1556 		  case 'l':
1557 #endif /* !_FFR_DPO_CS */
1558 			d->d_listenqueue = atoi(v);
1559 			break;
1560 
1561 		  case 'M':		/* modifiers (flags) */
1562 #if !_FFR_DPO_CS
1563 		  case 'm':
1564 #endif /* !_FFR_DPO_CS */
1565 			d->d_mflags = getmodifiers(v, d->d_flags);
1566 			break;
1567 
1568 		  case 'N':		/* name */
1569 #if !_FFR_DPO_CS
1570 		  case 'n':
1571 #endif /* !_FFR_DPO_CS */
1572 			d->d_name = v;
1573 			break;
1574 
1575 		  case 'P':		/* port */
1576 #if !_FFR_DPO_CS
1577 		  case 'p':
1578 #endif /* !_FFR_DPO_CS */
1579 			port = v;
1580 			break;
1581 
1582 		  case 'q':
1583 			d->d_queueLA = atoi(v);
1584 			break;
1585 
1586 		  case 'R':		/* receive buffer size */
1587 			d->d_tcprcvbufsize = atoi(v);
1588 			break;
1589 
1590 		  case 'r':
1591 			d->d_refuseLA = atoi(v);
1592 			break;
1593 
1594 		  case 'S':		/* send buffer size */
1595 #if !_FFR_DPO_CS
1596 		  case 's':
1597 #endif /* !_FFR_DPO_CS */
1598 			d->d_tcpsndbufsize = atoi(v);
1599 			break;
1600 
1601 #if _FFR_SS_PER_DAEMON
1602 		  case 'T':		/* SuperSafe */
1603 			if (tolower(*v) == 'i')
1604 				d->d_supersafe = SAFE_INTERACTIVE;
1605 			else if (tolower(*v) == 'p')
1606 # if MILTER
1607 				d->d_supersafe = SAFE_REALLY_POSTMILTER;
1608 # else /* MILTER */
1609 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1610 					"Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n");
1611 # endif /* MILTER */
1612 			else
1613 				d->d_supersafe = atobool(v) ? SAFE_REALLY
1614 							: SAFE_NO;
1615 			break;
1616 #endif /* _FFR_SS_PER_DAEMON */
1617 
1618 		  default:
1619 			syserr("554 5.3.5 PortOptions parameter \"%s\" unknown",
1620 			       f);
1621 		}
1622 	}
1623 
1624 	/* Check addr and port after finding family */
1625 	if (addr != NULL)
1626 	{
1627 		switch (d->d_addr.sa.sa_family)
1628 		{
1629 #if _FFR_DAEMON_NETUNIX
1630 # if NETUNIX
1631 		  case AF_UNIX:
1632 			if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path))
1633 			{
1634 				errno = ENAMETOOLONG;
1635 				syserr("setsockaddroptions: domain socket name too long: %s > %d",
1636 				       addr, sizeof(d->d_addr.sunix.sun_path));
1637 				break;
1638 			}
1639 
1640 			/* file safety check done in opendaemonsocket() */
1641 			(void) memset(&d->d_addr.sunix.sun_path, '\0',
1642 				      sizeof(d->d_addr.sunix.sun_path));
1643 			(void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path,
1644 					  addr,
1645 					  sizeof(d->d_addr.sunix.sun_path));
1646 			break;
1647 # endif /* NETUNIX */
1648 #endif	/* _FFR_DAEMON_NETUNIX */
1649 #if NETINET
1650 		  case AF_INET:
1651 			if (!isascii(*addr) || !isdigit(*addr) ||
1652 			    ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr))
1653 			     == INADDR_NONE))
1654 			{
1655 				register struct hostent *hp;
1656 
1657 				hp = sm_gethostbyname(addr, AF_INET);
1658 				if (hp == NULL)
1659 					syserr("554 5.3.0 host \"%s\" unknown",
1660 					       addr);
1661 				else
1662 				{
1663 					while (*(hp->h_addr_list) != NULL &&
1664 					       hp->h_addrtype != AF_INET)
1665 						hp->h_addr_list++;
1666 					if (*(hp->h_addr_list) == NULL)
1667 						syserr("554 5.3.0 host \"%s\" unknown",
1668 						       addr);
1669 					else
1670 						memmove(&d->d_addr.sin.sin_addr,
1671 							*(hp->h_addr_list),
1672 							INADDRSZ);
1673 # if NETINET6
1674 					freehostent(hp);
1675 					hp = NULL;
1676 # endif /* NETINET6 */
1677 				}
1678 			}
1679 			break;
1680 #endif /* NETINET */
1681 
1682 #if NETINET6
1683 		  case AF_INET6:
1684 			if (anynet_pton(AF_INET6, addr,
1685 					&d->d_addr.sin6.sin6_addr) != 1)
1686 			{
1687 				register struct hostent *hp;
1688 
1689 				hp = sm_gethostbyname(addr, AF_INET6);
1690 				if (hp == NULL)
1691 					syserr("554 5.3.0 host \"%s\" unknown",
1692 					       addr);
1693 				else
1694 				{
1695 					while (*(hp->h_addr_list) != NULL &&
1696 					       hp->h_addrtype != AF_INET6)
1697 						hp->h_addr_list++;
1698 					if (*(hp->h_addr_list) == NULL)
1699 						syserr("554 5.3.0 host \"%s\" unknown",
1700 						       addr);
1701 					else
1702 						memmove(&d->d_addr.sin6.sin6_addr,
1703 							*(hp->h_addr_list),
1704 							IN6ADDRSZ);
1705 					freehostent(hp);
1706 					hp = NULL;
1707 				}
1708 			}
1709 			break;
1710 #endif /* NETINET6 */
1711 
1712 		  default:
1713 			syserr("554 5.3.5 address= option unsupported for family %d",
1714 			       d->d_addr.sa.sa_family);
1715 			break;
1716 		}
1717 	}
1718 
1719 	if (port != NULL)
1720 	{
1721 		switch (d->d_addr.sa.sa_family)
1722 		{
1723 #if NETINET
1724 		  case AF_INET:
1725 			if (isascii(*port) && isdigit(*port))
1726 				d->d_addr.sin.sin_port = htons((unsigned short)
1727 						     atoi((const char *) port));
1728 			else
1729 			{
1730 # ifdef NO_GETSERVBYNAME
1731 				syserr("554 5.3.5 invalid port number: %s",
1732 				       port);
1733 # else /* NO_GETSERVBYNAME */
1734 				register struct servent *sp;
1735 
1736 				sp = getservbyname(port, "tcp");
1737 				if (sp == NULL)
1738 					syserr("554 5.3.5 service \"%s\" unknown",
1739 					       port);
1740 				else
1741 					d->d_addr.sin.sin_port = sp->s_port;
1742 # endif /* NO_GETSERVBYNAME */
1743 			}
1744 			break;
1745 #endif /* NETINET */
1746 
1747 #if NETINET6
1748 		  case AF_INET6:
1749 			if (isascii(*port) && isdigit(*port))
1750 				d->d_addr.sin6.sin6_port = htons((unsigned short)
1751 								  atoi(port));
1752 			else
1753 			{
1754 # ifdef NO_GETSERVBYNAME
1755 				syserr("554 5.3.5 invalid port number: %s",
1756 				       port);
1757 # else /* NO_GETSERVBYNAME */
1758 				register struct servent *sp;
1759 
1760 				sp = getservbyname(port, "tcp");
1761 				if (sp == NULL)
1762 					syserr("554 5.3.5 service \"%s\" unknown",
1763 					       port);
1764 				else
1765 					d->d_addr.sin6.sin6_port = sp->s_port;
1766 # endif /* NO_GETSERVBYNAME */
1767 			}
1768 			break;
1769 #endif /* NETINET6 */
1770 
1771 #if NETISO
1772 		  case AF_ISO:
1773 			/* assume two byte transport selector */
1774 			if (isascii(*port) && isdigit(*port))
1775 				portno = htons((unsigned short) atoi(port));
1776 			else
1777 			{
1778 # ifdef NO_GETSERVBYNAME
1779 				syserr("554 5.3.5 invalid port number: %s",
1780 				       port);
1781 # else /* NO_GETSERVBYNAME */
1782 				register struct servent *sp;
1783 
1784 				sp = getservbyname(port, "tcp");
1785 				if (sp == NULL)
1786 					syserr("554 5.3.5 service \"%s\" unknown",
1787 					       port);
1788 				else
1789 					portno = sp->s_port;
1790 # endif /* NO_GETSERVBYNAME */
1791 			}
1792 			memmove(TSEL(&d->d_addr.siso),
1793 				(char *) &portno, 2);
1794 			break;
1795 #endif /* NETISO */
1796 
1797 		  default:
1798 			syserr("554 5.3.5 Port= option unsupported for family %d",
1799 			       d->d_addr.sa.sa_family);
1800 			break;
1801 		}
1802 	}
1803 }
1804 /*
1805 **  SETDAEMONOPTIONS -- set options for running the MTA daemon
1806 **
1807 **	Parameters:
1808 **		p -- the options line.
1809 **
1810 **	Returns:
1811 **		true if successful, false otherwise.
1812 **
1813 **	Side Effects:
1814 **		increments number of daemons.
1815 */
1816 
1817 #define DEF_LISTENQUEUE	10
1818 
1819 struct dflags
1820 {
1821 	char	*d_name;
1822 	int	d_flag;
1823 };
1824 
1825 static struct dflags	DaemonFlags[] =
1826 {
1827 	{ "AUTHREQ",		D_AUTHREQ	},
1828 	{ "BINDIF",		D_BINDIF	},
1829 	{ "CANONREQ",		D_CANONREQ	},
1830 	{ "IFNHELO",		D_IFNHELO	},
1831 	{ "FQMAIL",		D_FQMAIL	},
1832 	{ "FQRCPT",		D_FQRCPT	},
1833 	{ "SMTPS",		D_SMTPS		},
1834 	{ "UNQUALOK",		D_UNQUALOK	},
1835 	{ "NOAUTH",		D_NOAUTH	},
1836 	{ "NOCANON",		D_NOCANON	},
1837 	{ "NOETRN",		D_NOETRN	},
1838 	{ "NOTLS",		D_NOTLS		},
1839 	{ "ETRNONLY",		D_ETRNONLY	},
1840 	{ "OPTIONAL",		D_OPTIONAL	},
1841 	{ "DISABLE",		D_DISABLE	},
1842 	{ "ISSET",		D_ISSET		},
1843 	{ NULL,			0		}
1844 };
1845 
1846 static void
1847 printdaemonflags(d)
1848 	DAEMON_T *d;
1849 {
1850 	register struct dflags *df;
1851 	bool first = true;
1852 
1853 	for (df = DaemonFlags; df->d_name != NULL; df++)
1854 	{
1855 		if (!bitnset(df->d_flag, d->d_flags))
1856 			continue;
1857 		if (first)
1858 			sm_dprintf("<%s", df->d_name);
1859 		else
1860 			sm_dprintf(",%s", df->d_name);
1861 		first = false;
1862 	}
1863 	if (!first)
1864 		sm_dprintf(">");
1865 }
1866 
1867 bool
1868 setdaemonoptions(p)
1869 	register char *p;
1870 {
1871 	if (NDaemons >= MAXDAEMONS)
1872 		return false;
1873 	Daemons[NDaemons].d_socket = -1;
1874 	Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
1875 	clrbitmap(Daemons[NDaemons].d_flags);
1876 	setsockaddroptions(p, &Daemons[NDaemons]);
1877 
1878 #if MILTER
1879 	if (Daemons[NDaemons].d_inputfilterlist != NULL)
1880 		Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist);
1881 #endif /* MILTER */
1882 
1883 	if (Daemons[NDaemons].d_name != NULL)
1884 		Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name);
1885 	else
1886 	{
1887 		char num[30];
1888 
1889 		(void) sm_snprintf(num, sizeof(num), "Daemon%d", NDaemons);
1890 		Daemons[NDaemons].d_name = newstr(num);
1891 	}
1892 
1893 	if (tTd(37, 1))
1894 	{
1895 		sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name);
1896 		printdaemonflags(&Daemons[NDaemons]);
1897 		sm_dprintf("\n");
1898 	}
1899 	++NDaemons;
1900 	return true;
1901 }
1902 /*
1903 **  INITDAEMON -- initialize daemon if not yet done.
1904 **
1905 **	Parameters:
1906 **		none
1907 **
1908 **	Returns:
1909 **		none
1910 **
1911 **	Side Effects:
1912 **		initializes structure for one daemon.
1913 */
1914 
1915 void
1916 initdaemon()
1917 {
1918 	if (NDaemons == 0)
1919 	{
1920 		Daemons[NDaemons].d_socket = -1;
1921 		Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
1922 		Daemons[NDaemons].d_name = "Daemon0";
1923 		NDaemons = 1;
1924 	}
1925 }
1926 /*
1927 **  SETCLIENTOPTIONS -- set options for running the client
1928 **
1929 **	Parameters:
1930 **		p -- the options line.
1931 **
1932 **	Returns:
1933 **		none.
1934 */
1935 
1936 static DAEMON_T	ClientSettings[AF_MAX + 1];
1937 
1938 void
1939 setclientoptions(p)
1940 	register char *p;
1941 {
1942 	int family;
1943 	DAEMON_T d;
1944 
1945 	memset(&d, '\0', sizeof(d));
1946 	setsockaddroptions(p, &d);
1947 
1948 	/* grab what we need */
1949 	family = d.d_addr.sa.sa_family;
1950 	STRUCTCOPY(d, ClientSettings[family]);
1951 	setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */
1952 	if (d.d_name != NULL)
1953 		ClientSettings[family].d_name = newstr(d.d_name);
1954 	else
1955 	{
1956 		char num[30];
1957 
1958 		(void) sm_snprintf(num, sizeof(num), "Client%d", family);
1959 		ClientSettings[family].d_name = newstr(num);
1960 	}
1961 }
1962 /*
1963 **  ADDR_FAMILY -- determine address family from address
1964 **
1965 **	Parameters:
1966 **		addr -- the string representation of the address
1967 **
1968 **	Returns:
1969 **		AF_INET, AF_INET6 or AF_UNSPEC
1970 **
1971 **	Side Effects:
1972 **		none.
1973 */
1974 
1975 static int
1976 addr_family(addr)
1977 	char *addr;
1978 {
1979 #if NETINET6
1980 	SOCKADDR clt_addr;
1981 #endif /* NETINET6 */
1982 
1983 #if NETINET
1984 	if (inet_addr(addr) != INADDR_NONE)
1985 	{
1986 		if (tTd(16, 9))
1987 			sm_dprintf("addr_family(%s): INET\n", addr);
1988 		return AF_INET;
1989 	}
1990 #endif /* NETINET */
1991 #if NETINET6
1992 	if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
1993 	{
1994 		if (tTd(16, 9))
1995 			sm_dprintf("addr_family(%s): INET6\n", addr);
1996 		return AF_INET6;
1997 	}
1998 #endif /* NETINET6 */
1999 #if _FFR_DAEMON_NETUNIX
2000 # if NETUNIX
2001 	if (*addr == '/')
2002 	{
2003 		if (tTd(16, 9))
2004 			sm_dprintf("addr_family(%s): LOCAL\n", addr);
2005 		return AF_UNIX;
2006 	}
2007 # endif /* NETUNIX */
2008 #endif	/* _FFR_DAEMON_NETUNIX */
2009 	if (tTd(16, 9))
2010 		sm_dprintf("addr_family(%s): UNSPEC\n", addr);
2011 	return AF_UNSPEC;
2012 }
2013 
2014 /*
2015 **  CHKCLIENTMODIFIERS -- check whether all clients have set a flag.
2016 **
2017 **	Parameters:
2018 **		flag -- the flag to test.
2019 **
2020 **	Returns:
2021 **		true iff all configured clients have set the flag.
2022 */
2023 
2024 bool
2025 chkclientmodifiers(flag)
2026 	int flag;
2027 {
2028 	int i;
2029 	bool flagisset;
2030 
2031 	flagisset = false;
2032 	for (i = 0; i < AF_MAX; i++)
2033 	{
2034 		if (bitnset(D_ISSET, ClientSettings[i].d_flags))
2035 		{
2036 			if (!bitnset((char) flag, ClientSettings[i].d_flags))
2037 				return false;
2038 			flagisset = true;
2039 		}
2040 	}
2041 	return flagisset;
2042 }
2043 
2044 #if MILTER
2045 /*
2046 **  SETUP_DAEMON_FILTERS -- Parse per-socket filters
2047 **
2048 **	Parameters:
2049 **		none
2050 **
2051 **	Returns:
2052 **		none
2053 */
2054 
2055 void
2056 setup_daemon_milters()
2057 {
2058 	int idx;
2059 
2060 	if (OpMode == MD_SMTP)
2061 	{
2062 		/* no need to configure the daemons */
2063 		return;
2064 	}
2065 
2066 	for (idx = 0; idx < NDaemons; idx++)
2067 	{
2068 		if (Daemons[idx].d_inputfilterlist != NULL)
2069 		{
2070 			milter_config(Daemons[idx].d_inputfilterlist,
2071 				      Daemons[idx].d_inputfilters,
2072 				      MAXFILTERS);
2073 		}
2074 	}
2075 }
2076 #endif /* MILTER */
2077 /*
2078 **  MAKECONNECTION -- make a connection to an SMTP socket on a machine.
2079 **
2080 **	Parameters:
2081 **		host -- the name of the host.
2082 **		port -- the port number to connect to.
2083 **		mci -- a pointer to the mail connection information
2084 **			structure to be filled in.
2085 **		e -- the current envelope.
2086 **		enough -- time at which to stop further connection attempts.
2087 **			(0 means no limit)
2088 **
2089 **	Returns:
2090 **		An exit code telling whether the connection could be
2091 **			made and if not why not.
2092 **
2093 **	Side Effects:
2094 **		none.
2095 */
2096 
2097 static jmp_buf	CtxConnectTimeout;
2098 
2099 SOCKADDR	CurHostAddr;		/* address of current host */
2100 
2101 int
2102 makeconnection(host, port, mci, e, enough)
2103 	char *host;
2104 	volatile unsigned int port;
2105 	register MCI *mci;
2106 	ENVELOPE *e;
2107 	time_t enough;
2108 {
2109 	register volatile int addrno = 0;
2110 	volatile int s;
2111 	register struct hostent *volatile hp = (struct hostent *) NULL;
2112 	SOCKADDR addr;
2113 	SOCKADDR clt_addr;
2114 	int save_errno = 0;
2115 	volatile SOCKADDR_LEN_T addrlen;
2116 	volatile bool firstconnect = true;
2117 	SM_EVENT *volatile ev = NULL;
2118 #if NETINET6
2119 	volatile bool v6found = false;
2120 #endif /* NETINET6 */
2121 	volatile int family = InetMode;
2122 	SOCKADDR_LEN_T len;
2123 	volatile SOCKADDR_LEN_T socksize = 0;
2124 	volatile bool clt_bind;
2125 	BITMAP256 d_flags;
2126 	char *p;
2127 	extern ENVELOPE BlankEnvelope;
2128 
2129 	/* retranslate {daemon_flags} into bitmap */
2130 	clrbitmap(d_flags);
2131 	if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL)
2132 	{
2133 		for (; *p != '\0'; p++)
2134 		{
2135 			if (!(isascii(*p) && isspace(*p)))
2136 				setbitn(bitidx(*p), d_flags);
2137 		}
2138 	}
2139 
2140 #if NETINET6
2141  v4retry:
2142 #endif /* NETINET6 */
2143 	clt_bind = false;
2144 
2145 	/* Set up the address for outgoing connection. */
2146 	if (bitnset(D_BINDIF, d_flags) &&
2147 	    (p = macvalue(macid("{if_addr}"), e)) != NULL &&
2148 	    *p != '\0')
2149 	{
2150 #if NETINET6
2151 		char p6[INET6_ADDRSTRLEN];
2152 #endif /* NETINET6 */
2153 
2154 		memset(&clt_addr, '\0', sizeof(clt_addr));
2155 
2156 		/* infer the address family from the address itself */
2157 		clt_addr.sa.sa_family = addr_family(p);
2158 		switch (clt_addr.sa.sa_family)
2159 		{
2160 #if NETINET
2161 		  case AF_INET:
2162 			clt_addr.sin.sin_addr.s_addr = inet_addr(p);
2163 			if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE &&
2164 			    clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK)
2165 			{
2166 				clt_bind = true;
2167 				socksize = sizeof(struct sockaddr_in);
2168 			}
2169 			break;
2170 #endif /* NETINET */
2171 
2172 #if NETINET6
2173 		  case AF_INET6:
2174 			if (inet_addr(p) != INADDR_NONE)
2175 				(void) sm_snprintf(p6, sizeof(p6),
2176 						   "IPv6:::ffff:%s", p);
2177 			else
2178 				(void) sm_strlcpy(p6, p, sizeof(p6));
2179 			if (anynet_pton(AF_INET6, p6,
2180 					&clt_addr.sin6.sin6_addr) == 1 &&
2181 			    !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr))
2182 			{
2183 				clt_bind = true;
2184 				socksize = sizeof(struct sockaddr_in6);
2185 			}
2186 			break;
2187 #endif /* NETINET6 */
2188 
2189 #if 0
2190 		  default:
2191 			syserr("554 5.3.5 Address= option unsupported for family %d",
2192 			       clt_addr.sa.sa_family);
2193 			break;
2194 #endif /* 0 */
2195 		}
2196 		if (clt_bind)
2197 			family = clt_addr.sa.sa_family;
2198 	}
2199 
2200 	/* D_BINDIF not set or not available, fallback to ClientPortOptions */
2201 	if (!clt_bind)
2202 	{
2203 		STRUCTCOPY(ClientSettings[family].d_addr, clt_addr);
2204 		switch (clt_addr.sa.sa_family)
2205 		{
2206 #if NETINET
2207 		  case AF_INET:
2208 			if (clt_addr.sin.sin_addr.s_addr == 0)
2209 				clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
2210 			else
2211 				clt_bind = true;
2212 			if (clt_addr.sin.sin_port != 0)
2213 				clt_bind = true;
2214 			socksize = sizeof(struct sockaddr_in);
2215 			break;
2216 #endif /* NETINET */
2217 #if NETINET6
2218 		  case AF_INET6:
2219 			if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
2220 				clt_addr.sin6.sin6_addr = in6addr_any;
2221 			else
2222 				clt_bind = true;
2223 			socksize = sizeof(struct sockaddr_in6);
2224 			if (clt_addr.sin6.sin6_port != 0)
2225 				clt_bind = true;
2226 			break;
2227 #endif /* NETINET6 */
2228 #if NETISO
2229 		  case AF_ISO:
2230 			socksize = sizeof(clt_addr.siso);
2231 			clt_bind = true;
2232 			break;
2233 #endif /* NETISO */
2234 		  default:
2235 			break;
2236 		}
2237 	}
2238 
2239 	/*
2240 	**  Set up the address for the mailer.
2241 	**	Accept "[a.b.c.d]" syntax for host name.
2242 	*/
2243 
2244 	SM_SET_H_ERRNO(0);
2245 	errno = 0;
2246 	memset(&CurHostAddr, '\0', sizeof(CurHostAddr));
2247 	memset(&addr, '\0', sizeof(addr));
2248 	SmtpPhase = mci->mci_phase = "initial connection";
2249 	CurHostName = host;
2250 
2251 	if (host[0] == '[')
2252 	{
2253 		p = strchr(host, ']');
2254 		if (p != NULL)
2255 		{
2256 #if NETINET
2257 			unsigned long hid = INADDR_NONE;
2258 #endif /* NETINET */
2259 #if NETINET6
2260 			struct sockaddr_in6 hid6;
2261 #endif /* NETINET6 */
2262 
2263 			*p = '\0';
2264 #if NETINET6
2265 			memset(&hid6, '\0', sizeof(hid6));
2266 #endif /* NETINET6 */
2267 #if NETINET
2268 			if (family == AF_INET &&
2269 			    (hid = inet_addr(&host[1])) != INADDR_NONE)
2270 			{
2271 				addr.sin.sin_family = AF_INET;
2272 				addr.sin.sin_addr.s_addr = hid;
2273 			}
2274 			else
2275 #endif /* NETINET */
2276 #if NETINET6
2277 			if (family == AF_INET6 &&
2278 			    anynet_pton(AF_INET6, &host[1],
2279 					&hid6.sin6_addr) == 1)
2280 			{
2281 				addr.sin6.sin6_family = AF_INET6;
2282 				addr.sin6.sin6_addr = hid6.sin6_addr;
2283 			}
2284 			else
2285 #endif /* NETINET6 */
2286 			{
2287 				/* try it as a host name (avoid MX lookup) */
2288 				hp = sm_gethostbyname(&host[1], family);
2289 				if (hp == NULL && p[-1] == '.')
2290 				{
2291 #if NAMED_BIND
2292 					int oldopts = _res.options;
2293 
2294 					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
2295 #endif /* NAMED_BIND */
2296 					p[-1] = '\0';
2297 					hp = sm_gethostbyname(&host[1],
2298 							      family);
2299 					p[-1] = '.';
2300 #if NAMED_BIND
2301 					_res.options = oldopts;
2302 #endif /* NAMED_BIND */
2303 				}
2304 				*p = ']';
2305 				goto gothostent;
2306 			}
2307 			*p = ']';
2308 		}
2309 		if (p == NULL)
2310 		{
2311 			extern char MsgBuf[];
2312 
2313 			usrerrenh("5.1.2",
2314 				  "553 Invalid numeric domain spec \"%s\"",
2315 				  host);
2316 			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
2317 			errno = EINVAL;
2318 			return EX_NOHOST;
2319 		}
2320 	}
2321 	else
2322 	{
2323 		/* contortion to get around SGI cc complaints */
2324 		{
2325 			p = &host[strlen(host) - 1];
2326 			hp = sm_gethostbyname(host, family);
2327 			if (hp == NULL && *p == '.')
2328 			{
2329 #if NAMED_BIND
2330 				int oldopts = _res.options;
2331 
2332 				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
2333 #endif /* NAMED_BIND */
2334 				*p = '\0';
2335 				hp = sm_gethostbyname(host, family);
2336 				*p = '.';
2337 #if NAMED_BIND
2338 				_res.options = oldopts;
2339 #endif /* NAMED_BIND */
2340 			}
2341 		}
2342 gothostent:
2343 		if (hp == NULL)
2344 		{
2345 #if NAMED_BIND
2346 			/* check for name server timeouts */
2347 # if NETINET6
2348 			if (WorkAroundBrokenAAAA && family == AF_INET6 &&
2349 			    errno == ETIMEDOUT)
2350 			{
2351 				/*
2352 				**  An attempt with family AF_INET may
2353 				**  succeed By skipping the next section
2354 				**  of code, we will try AF_INET before
2355 				**  failing.
2356 				*/
2357 
2358 				if (tTd(16, 10))
2359 					sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n");
2360 			}
2361 			else
2362 # endif /* NETINET6 */
2363 			{
2364 				if (errno == ETIMEDOUT ||
2365 # if _FFR_GETHBN_ExFILE
2366 #  ifdef EMFILE
2367 				   errno == EMFILE ||
2368 #  endif /* EMFILE */
2369 #  ifdef ENFILE
2370 				   errno == ENFILE ||
2371 #  endif /* ENFILE */
2372 # endif /* _FFR_GETHBN_ExFILE */
2373 				    h_errno == TRY_AGAIN ||
2374 				    (errno == ECONNREFUSED && UseNameServer))
2375 				{
2376 					save_errno = errno;
2377 					mci_setstat(mci, EX_TEMPFAIL,
2378 						    "4.4.3", NULL);
2379 					errno = save_errno;
2380 					return EX_TEMPFAIL;
2381 				}
2382 			}
2383 #endif /* NAMED_BIND */
2384 #if NETINET6
2385 			/*
2386 			**  Try v6 first, then fall back to v4.
2387 			**  If we found a v6 address, but no v4
2388 			**  addresses, then TEMPFAIL.
2389 			*/
2390 
2391 			if (family == AF_INET6)
2392 			{
2393 				family = AF_INET;
2394 				goto v4retry;
2395 			}
2396 			if (v6found)
2397 				goto v6tempfail;
2398 #endif /* NETINET6 */
2399 			save_errno = errno;
2400 			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2401 			errno = save_errno;
2402 			return EX_NOHOST;
2403 		}
2404 		addr.sa.sa_family = hp->h_addrtype;
2405 		switch (hp->h_addrtype)
2406 		{
2407 #if NETINET
2408 		  case AF_INET:
2409 			memmove(&addr.sin.sin_addr,
2410 				hp->h_addr,
2411 				INADDRSZ);
2412 			break;
2413 #endif /* NETINET */
2414 
2415 #if NETINET6
2416 		  case AF_INET6:
2417 			memmove(&addr.sin6.sin6_addr,
2418 				hp->h_addr,
2419 				IN6ADDRSZ);
2420 			break;
2421 #endif /* NETINET6 */
2422 
2423 		  default:
2424 			if (hp->h_length > sizeof(addr.sa.sa_data))
2425 			{
2426 				syserr("makeconnection: long sa_data: family %d len %d",
2427 					hp->h_addrtype, hp->h_length);
2428 				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2429 				errno = EINVAL;
2430 				return EX_NOHOST;
2431 			}
2432 			memmove(addr.sa.sa_data, hp->h_addr, hp->h_length);
2433 			break;
2434 		}
2435 		addrno = 1;
2436 	}
2437 
2438 	/*
2439 	**  Determine the port number.
2440 	*/
2441 
2442 	if (port == 0)
2443 	{
2444 #ifdef NO_GETSERVBYNAME
2445 		port = htons(25);
2446 #else /* NO_GETSERVBYNAME */
2447 		register struct servent *sp = getservbyname("smtp", "tcp");
2448 
2449 		if (sp == NULL)
2450 		{
2451 			if (LogLevel > 2)
2452 				sm_syslog(LOG_ERR, NOQID,
2453 					  "makeconnection: service \"smtp\" unknown");
2454 			port = htons(25);
2455 		}
2456 		else
2457 			port = sp->s_port;
2458 #endif /* NO_GETSERVBYNAME */
2459 	}
2460 
2461 #if NETINET6
2462 	if (addr.sa.sa_family == AF_INET6 &&
2463 	    IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) &&
2464 	    ClientSettings[AF_INET].d_addr.sa.sa_family != 0)
2465 	{
2466 		/*
2467 		**  Ignore mapped IPv4 address since
2468 		**  there is a ClientPortOptions setting
2469 		**  for IPv4.
2470 		*/
2471 
2472 		goto nextaddr;
2473 	}
2474 #endif /* NETINET6 */
2475 
2476 	switch (addr.sa.sa_family)
2477 	{
2478 #if NETINET
2479 	  case AF_INET:
2480 		addr.sin.sin_port = port;
2481 		addrlen = sizeof(struct sockaddr_in);
2482 		break;
2483 #endif /* NETINET */
2484 
2485 #if NETINET6
2486 	  case AF_INET6:
2487 		addr.sin6.sin6_port = port;
2488 		addrlen = sizeof(struct sockaddr_in6);
2489 		break;
2490 #endif /* NETINET6 */
2491 
2492 #if NETISO
2493 	  case AF_ISO:
2494 		/* assume two byte transport selector */
2495 		memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
2496 		addrlen = sizeof(struct sockaddr_iso);
2497 		break;
2498 #endif /* NETISO */
2499 
2500 	  default:
2501 		syserr("Can't connect to address family %d", addr.sa.sa_family);
2502 		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2503 		errno = EINVAL;
2504 #if NETINET6
2505 		if (hp != NULL)
2506 			freehostent(hp);
2507 #endif /* NETINET6 */
2508 		return EX_NOHOST;
2509 	}
2510 
2511 	/*
2512 	**  Try to actually open the connection.
2513 	*/
2514 
2515 #if XLA
2516 	/* if too many connections, don't bother trying */
2517 	if (!xla_noqueue_ok(host))
2518 	{
2519 # if NETINET6
2520 		if (hp != NULL)
2521 			freehostent(hp);
2522 # endif /* NETINET6 */
2523 		return EX_TEMPFAIL;
2524 	}
2525 #endif /* XLA */
2526 
2527 	for (;;)
2528 	{
2529 		if (tTd(16, 1))
2530 			sm_dprintf("makeconnection (%s [%s].%d (%d))\n",
2531 				   host, anynet_ntoa(&addr), ntohs(port),
2532 				   (int) addr.sa.sa_family);
2533 
2534 		/* save for logging */
2535 		CurHostAddr = addr;
2536 
2537 #if HASRRESVPORT
2538 		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
2539 		{
2540 			int rport = IPPORT_RESERVED - 1;
2541 
2542 			s = rresvport(&rport);
2543 		}
2544 		else
2545 #endif /* HASRRESVPORT */
2546 		{
2547 			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
2548 		}
2549 		if (s < 0)
2550 		{
2551 			save_errno = errno;
2552 			syserr("makeconnection: cannot create socket");
2553 #if XLA
2554 			xla_host_end(host);
2555 #endif /* XLA */
2556 			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2557 #if NETINET6
2558 			if (hp != NULL)
2559 				freehostent(hp);
2560 #endif /* NETINET6 */
2561 			errno = save_errno;
2562 			return EX_TEMPFAIL;
2563 		}
2564 
2565 #ifdef SO_SNDBUF
2566 		if (ClientSettings[family].d_tcpsndbufsize > 0)
2567 		{
2568 			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
2569 				       (char *) &ClientSettings[family].d_tcpsndbufsize,
2570 				       sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0)
2571 				syserr("makeconnection: setsockopt(SO_SNDBUF)");
2572 		}
2573 #endif /* SO_SNDBUF */
2574 #ifdef SO_RCVBUF
2575 		if (ClientSettings[family].d_tcprcvbufsize > 0)
2576 		{
2577 			if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
2578 				       (char *) &ClientSettings[family].d_tcprcvbufsize,
2579 				       sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0)
2580 				syserr("makeconnection: setsockopt(SO_RCVBUF)");
2581 		}
2582 #endif /* SO_RCVBUF */
2583 
2584 		if (tTd(16, 1))
2585 			sm_dprintf("makeconnection: fd=%d\n", s);
2586 
2587 		/* turn on network debugging? */
2588 		if (tTd(16, 101))
2589 		{
2590 			int on = 1;
2591 
2592 			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
2593 					  (char *)&on, sizeof(on));
2594 		}
2595 		if (e->e_xfp != NULL)	/* for debugging */
2596 			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
2597 		errno = 0;		/* for debugging */
2598 
2599 		if (clt_bind)
2600 		{
2601 			int on = 1;
2602 
2603 			switch (clt_addr.sa.sa_family)
2604 			{
2605 #if NETINET
2606 			  case AF_INET:
2607 				if (clt_addr.sin.sin_port != 0)
2608 					(void) setsockopt(s, SOL_SOCKET,
2609 							  SO_REUSEADDR,
2610 							  (char *) &on,
2611 							  sizeof(on));
2612 				break;
2613 #endif /* NETINET */
2614 
2615 #if NETINET6
2616 			  case AF_INET6:
2617 				if (clt_addr.sin6.sin6_port != 0)
2618 					(void) setsockopt(s, SOL_SOCKET,
2619 							  SO_REUSEADDR,
2620 							  (char *) &on,
2621 							  sizeof(on));
2622 				break;
2623 #endif /* NETINET6 */
2624 			}
2625 
2626 			if (bind(s, &clt_addr.sa, socksize) < 0)
2627 			{
2628 				save_errno = errno;
2629 				(void) close(s);
2630 				errno = save_errno;
2631 				syserr("makeconnection: cannot bind socket [%s]",
2632 				       anynet_ntoa(&clt_addr));
2633 #if NETINET6
2634 				if (hp != NULL)
2635 					freehostent(hp);
2636 #endif /* NETINET6 */
2637 				errno = save_errno;
2638 				return EX_TEMPFAIL;
2639 			}
2640 		}
2641 
2642 		/*
2643 		**  Linux seems to hang in connect for 90 minutes (!!!).
2644 		**  Time out the connect to avoid this problem.
2645 		*/
2646 
2647 		if (setjmp(CtxConnectTimeout) == 0)
2648 		{
2649 			int i;
2650 
2651 			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
2652 				ev = sm_setevent(TimeOuts.to_iconnect,
2653 						 connecttimeout, 0);
2654 			else if (TimeOuts.to_connect != 0)
2655 				ev = sm_setevent(TimeOuts.to_connect,
2656 						 connecttimeout, 0);
2657 			else
2658 				ev = NULL;
2659 
2660 			switch (ConnectOnlyTo.sa.sa_family)
2661 			{
2662 #if NETINET
2663 			  case AF_INET:
2664 				addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
2665 				break;
2666 #endif /* NETINET */
2667 
2668 #if NETINET6
2669 			  case AF_INET6:
2670 				memmove(&addr.sin6.sin6_addr,
2671 					&ConnectOnlyTo.sin6.sin6_addr,
2672 					IN6ADDRSZ);
2673 				break;
2674 #endif /* NETINET6 */
2675 			}
2676 			if (tTd(16, 1))
2677 				sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr));
2678 			i = connect(s, (struct sockaddr *) &addr, addrlen);
2679 			save_errno = errno;
2680 			if (ev != NULL)
2681 				sm_clrevent(ev);
2682 			if (i >= 0)
2683 				break;
2684 		}
2685 		else
2686 			save_errno = errno;
2687 
2688 		/* couldn't connect.... figure out why */
2689 		(void) close(s);
2690 
2691 		/* if running demand-dialed connection, try again */
2692 		if (DialDelay > 0 && firstconnect &&
2693 		    bitnset(M_DIALDELAY, mci->mci_mailer->m_flags))
2694 		{
2695 			if (tTd(16, 1))
2696 				sm_dprintf("Connect failed (%s); trying again...\n",
2697 					   sm_errstring(save_errno));
2698 			firstconnect = false;
2699 			(void) sleep(DialDelay);
2700 			continue;
2701 		}
2702 
2703 		if (LogLevel > 13)
2704 			sm_syslog(LOG_INFO, e->e_id,
2705 				  "makeconnection (%s [%s]) failed: %s",
2706 				  host, anynet_ntoa(&addr),
2707 				  sm_errstring(save_errno));
2708 
2709 #if NETINET6
2710 nextaddr:
2711 #endif /* NETINET6 */
2712 		if (hp != NULL && hp->h_addr_list[addrno] != NULL &&
2713 		    (enough == 0 || curtime() < enough))
2714 		{
2715 			if (tTd(16, 1))
2716 				sm_dprintf("Connect failed (%s); trying new address....\n",
2717 					   sm_errstring(save_errno));
2718 			switch (addr.sa.sa_family)
2719 			{
2720 #if NETINET
2721 			  case AF_INET:
2722 				memmove(&addr.sin.sin_addr,
2723 					hp->h_addr_list[addrno++],
2724 					INADDRSZ);
2725 				break;
2726 #endif /* NETINET */
2727 
2728 #if NETINET6
2729 			  case AF_INET6:
2730 				memmove(&addr.sin6.sin6_addr,
2731 					hp->h_addr_list[addrno++],
2732 					IN6ADDRSZ);
2733 				break;
2734 #endif /* NETINET6 */
2735 
2736 			  default:
2737 				memmove(addr.sa.sa_data,
2738 					hp->h_addr_list[addrno++],
2739 					hp->h_length);
2740 				break;
2741 			}
2742 			continue;
2743 		}
2744 		errno = save_errno;
2745 
2746 #if NETINET6
2747 		if (family == AF_INET6)
2748 		{
2749 			if (tTd(16, 1))
2750 				sm_dprintf("Connect failed (%s); retrying with AF_INET....\n",
2751 					   sm_errstring(save_errno));
2752 			v6found = true;
2753 			family = AF_INET;
2754 			if (hp != NULL)
2755 			{
2756 				freehostent(hp);
2757 				hp = NULL;
2758 			}
2759 			goto v4retry;
2760 		}
2761 	v6tempfail:
2762 #endif /* NETINET6 */
2763 		/* couldn't open connection */
2764 #if NETINET6
2765 		/* Don't clobber an already saved errno from v4retry */
2766 		if (errno > 0)
2767 #endif /* NETINET6 */
2768 			save_errno = errno;
2769 		if (tTd(16, 1))
2770 			sm_dprintf("Connect failed (%s)\n",
2771 				   sm_errstring(save_errno));
2772 #if XLA
2773 		xla_host_end(host);
2774 #endif /* XLA */
2775 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2776 #if NETINET6
2777 		if (hp != NULL)
2778 			freehostent(hp);
2779 #endif /* NETINET6 */
2780 		errno = save_errno;
2781 		return EX_TEMPFAIL;
2782 	}
2783 
2784 #if NETINET6
2785 	if (hp != NULL)
2786 	{
2787 		freehostent(hp);
2788 		hp = NULL;
2789 	}
2790 #endif /* NETINET6 */
2791 
2792 	/* connection ok, put it into canonical form */
2793 	mci->mci_out = NULL;
2794 	if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2795 				       (void *) &s,
2796 				       SM_IO_WRONLY_B, NULL)) == NULL ||
2797 	    (s = dup(s)) < 0 ||
2798 	    (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2799 				      (void *) &s,
2800 				      SM_IO_RDONLY_B, NULL)) == NULL)
2801 	{
2802 		save_errno = errno;
2803 		syserr("cannot open SMTP client channel, fd=%d", s);
2804 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2805 		if (mci->mci_out != NULL)
2806 			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2807 		(void) close(s);
2808 		errno = save_errno;
2809 		return EX_TEMPFAIL;
2810 	}
2811 	sm_io_automode(mci->mci_out, mci->mci_in);
2812 
2813 	/* set {client_flags} */
2814 	if (ClientSettings[addr.sa.sa_family].d_mflags != NULL)
2815 	{
2816 		macdefine(&mci->mci_macro, A_PERM,
2817 			  macid("{client_flags}"),
2818 			  ClientSettings[addr.sa.sa_family].d_mflags);
2819 	}
2820 	else
2821 		macdefine(&mci->mci_macro, A_PERM,
2822 			  macid("{client_flags}"), "");
2823 
2824 	/* "add" {client_flags} to bitmap */
2825 	if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags))
2826 	{
2827 		/* look for just this one flag */
2828 		setbitn(D_IFNHELO, d_flags);
2829 	}
2830 
2831 	/* find out name for Interface through which we connect */
2832 	len = sizeof(addr);
2833 	if (getsockname(s, &addr.sa, &len) == 0)
2834 	{
2835 		char *name;
2836 		char family[5];
2837 
2838 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2839 			macid("{if_addr_out}"), anynet_ntoa(&addr));
2840 		(void) sm_snprintf(family, sizeof(family), "%d",
2841 			addr.sa.sa_family);
2842 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2843 			macid("{if_family_out}"), family);
2844 
2845 		name = hostnamebyanyaddr(&addr);
2846 		macdefine(&BlankEnvelope.e_macro, A_TEMP,
2847 			macid("{if_name_out}"), name);
2848 		if (LogLevel > 11)
2849 		{
2850 			/* log connection information */
2851 			sm_syslog(LOG_INFO, e->e_id,
2852 				  "SMTP outgoing connect on %.40s", name);
2853 		}
2854 		if (bitnset(D_IFNHELO, d_flags))
2855 		{
2856 			if (name[0] != '[' && strchr(name, '.') != NULL)
2857 				mci->mci_heloname = newstr(name);
2858 		}
2859 	}
2860 	else
2861 	{
2862 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2863 			macid("{if_name_out}"), NULL);
2864 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2865 			macid("{if_addr_out}"), NULL);
2866 		macdefine(&BlankEnvelope.e_macro, A_PERM,
2867 			macid("{if_family_out}"), NULL);
2868 	}
2869 
2870 	/* Use the configured HeloName as appropriate */
2871 	if (HeloName != NULL && HeloName[0] != '\0')
2872 		mci->mci_heloname = newstr(HeloName);
2873 
2874 	mci_setstat(mci, EX_OK, NULL, NULL);
2875 	return EX_OK;
2876 }
2877 
2878 static void
2879 connecttimeout(ignore)
2880 	int ignore;
2881 {
2882 	/*
2883 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2884 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2885 	**	DOING.
2886 	*/
2887 
2888 	errno = ETIMEDOUT;
2889 	longjmp(CtxConnectTimeout, 1);
2890 }
2891 /*
2892 **  MAKECONNECTION_DS -- make a connection to a domain socket.
2893 **
2894 **	Parameters:
2895 **		mux_path -- the path of the socket to connect to.
2896 **		mci -- a pointer to the mail connection information
2897 **			structure to be filled in.
2898 **
2899 **	Returns:
2900 **		An exit code telling whether the connection could be
2901 **			made and if not why not.
2902 **
2903 **	Side Effects:
2904 **		none.
2905 */
2906 
2907 #if NETUNIX
2908 int
2909 makeconnection_ds(mux_path, mci)
2910 	char *mux_path;
2911 	register MCI *mci;
2912 {
2913 	int sock;
2914 	int rval, save_errno;
2915 	long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
2916 	struct sockaddr_un unix_addr;
2917 
2918 	/* if not safe, don't connect */
2919 	rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
2920 			sff, S_IRUSR|S_IWUSR, NULL);
2921 
2922 	if (rval != 0)
2923 	{
2924 		syserr("makeconnection_ds: unsafe domain socket %s",
2925 			mux_path);
2926 		mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
2927 		errno = rval;
2928 		return EX_TEMPFAIL;
2929 	}
2930 
2931 	/* prepare address structure */
2932 	memset(&unix_addr, '\0', sizeof(unix_addr));
2933 	unix_addr.sun_family = AF_UNIX;
2934 
2935 	if (strlen(mux_path) >= sizeof(unix_addr.sun_path))
2936 	{
2937 		syserr("makeconnection_ds: domain socket name %s too long",
2938 			mux_path);
2939 
2940 		/* XXX why TEMPFAIL but 5.x.y ? */
2941 		mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
2942 		errno = ENAMETOOLONG;
2943 		return EX_UNAVAILABLE;
2944 	}
2945 	(void) sm_strlcpy(unix_addr.sun_path, mux_path,
2946 			  sizeof(unix_addr.sun_path));
2947 
2948 	/* initialize domain socket */
2949 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
2950 	if (sock == -1)
2951 	{
2952 		save_errno = errno;
2953 		syserr("makeconnection_ds: could not create domain socket %s",
2954 			mux_path);
2955 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2956 		errno = save_errno;
2957 		return EX_TEMPFAIL;
2958 	}
2959 
2960 	/* connect to server */
2961 	if (connect(sock, (struct sockaddr *) &unix_addr,
2962 		    sizeof(unix_addr)) == -1)
2963 	{
2964 		save_errno = errno;
2965 		syserr("Could not connect to socket %s", mux_path);
2966 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2967 		(void) close(sock);
2968 		errno = save_errno;
2969 		return EX_TEMPFAIL;
2970 	}
2971 
2972 	/* connection ok, put it into canonical form */
2973 	mci->mci_out = NULL;
2974 	if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2975 				       (void *) &sock, SM_IO_WRONLY_B, NULL))
2976 					== NULL
2977 	    || (sock = dup(sock)) < 0 ||
2978 	    (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2979 				      (void *) &sock, SM_IO_RDONLY_B, NULL))
2980 					== NULL)
2981 	{
2982 		save_errno = errno;
2983 		syserr("cannot open SMTP client channel, fd=%d", sock);
2984 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2985 		if (mci->mci_out != NULL)
2986 			(void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2987 		(void) close(sock);
2988 		errno = save_errno;
2989 		return EX_TEMPFAIL;
2990 	}
2991 	sm_io_automode(mci->mci_out, mci->mci_in);
2992 
2993 	mci_setstat(mci, EX_OK, NULL, NULL);
2994 	errno = 0;
2995 	return EX_OK;
2996 }
2997 #endif /* NETUNIX */
2998 /*
2999 **  SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
3000 **
3001 **	Parameters:
3002 **		none.
3003 **
3004 **	Returns:
3005 **		none.
3006 **
3007 **	Side Effects:
3008 **		closes control socket, exits.
3009 */
3010 
3011 void
3012 shutdown_daemon()
3013 {
3014 	int i;
3015 	char *reason;
3016 
3017 	sm_allsignals(true);
3018 
3019 	reason = ShutdownRequest;
3020 	ShutdownRequest = NULL;
3021 	PendingSignal = 0;
3022 
3023 	if (LogLevel > 9)
3024 		sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s",
3025 			  reason == NULL ? "implicit call" : reason);
3026 
3027 	FileName = NULL;
3028 	closecontrolsocket(true);
3029 #if XLA
3030 	xla_all_end();
3031 #endif /* XLA */
3032 
3033 	for (i = 0; i < NDaemons; i++)
3034 	{
3035 		if (Daemons[i].d_socket >= 0)
3036 		{
3037 			(void) close(Daemons[i].d_socket);
3038 			Daemons[i].d_socket = -1;
3039 
3040 #if _FFR_DAEMON_NETUNIX
3041 # if NETUNIX
3042 			/* Remove named sockets */
3043 			if (Daemons[i].d_addr.sa.sa_family == AF_UNIX)
3044 			{
3045 				int rval;
3046 				long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT;
3047 
3048 				/* if not safe, don't use it */
3049 				rval = safefile(Daemons[i].d_addr.sunix.sun_path,
3050 						RunAsUid, RunAsGid,
3051 						RunAsUserName, sff,
3052 						S_IRUSR|S_IWUSR, NULL);
3053 				if (rval == 0 &&
3054 				    unlink(Daemons[i].d_addr.sunix.sun_path) < 0)
3055 				{
3056 					sm_syslog(LOG_WARNING, NOQID,
3057 						  "Could not remove daemon %s socket: %s: %s",
3058 						  Daemons[i].d_name,
3059 						  Daemons[i].d_addr.sunix.sun_path,
3060 						  sm_errstring(errno));
3061 				}
3062 			}
3063 # endif /* NETUNIX */
3064 #endif	/* _FFR_DAEMON_NETUNIX */
3065 		}
3066 	}
3067 
3068 	finis(false, true, EX_OK);
3069 }
3070 /*
3071 **  RESTART_DAEMON -- Performs a clean restart of the daemon
3072 **
3073 **	Parameters:
3074 **		none.
3075 **
3076 **	Returns:
3077 **		none.
3078 **
3079 **	Side Effects:
3080 **		restarts the daemon or exits if restart fails.
3081 */
3082 
3083 /* Make a non-DFL/IGN signal a noop */
3084 #define SM_NOOP_SIGNAL(sig, old)				\
3085 do								\
3086 {								\
3087 	(old) = sm_signal((sig), sm_signal_noop);		\
3088 	if ((old) == SIG_IGN || (old) == SIG_DFL)		\
3089 		(void) sm_signal((sig), (old));			\
3090 } while (0)
3091 
3092 void
3093 restart_daemon()
3094 {
3095 	bool drop;
3096 	int save_errno;
3097 	char *reason;
3098 	sigfunc_t ignore, oalrm, ousr1;
3099 	extern int DtableSize;
3100 
3101 	/* clear the events to turn off SIGALRMs */
3102 	sm_clear_events();
3103 	sm_allsignals(true);
3104 
3105 	reason = RestartRequest;
3106 	RestartRequest = NULL;
3107 	PendingSignal = 0;
3108 
3109 	if (SaveArgv[0][0] != '/')
3110 	{
3111 		if (LogLevel > 3)
3112 			sm_syslog(LOG_INFO, NOQID,
3113 				  "could not restart: need full path");
3114 		finis(false, true, EX_OSFILE);
3115 		/* NOTREACHED */
3116 	}
3117 	if (LogLevel > 3)
3118 		sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s",
3119 			  SaveArgv[0],
3120 			  reason == NULL ? "implicit call" : reason);
3121 
3122 	closecontrolsocket(true);
3123 #if SM_CONF_SHM
3124 	cleanup_shm(DaemonPid == getpid());
3125 #endif /* SM_CONF_SHM */
3126 
3127 	/* close locked pid file */
3128 	close_sendmail_pid();
3129 
3130 	/*
3131 	**  Want to drop to the user who started the process in all cases
3132 	**  *but* when running as "smmsp" for the clientmqueue queue run
3133 	**  daemon.  In that case, UseMSP will be true, RunAsUid should not
3134 	**  be root, and RealUid should be either 0 or RunAsUid.
3135 	*/
3136 
3137 	drop = !(UseMSP && RunAsUid != 0 &&
3138 		 (RealUid == 0 || RealUid == RunAsUid));
3139 
3140 	if (drop_privileges(drop) != EX_OK)
3141 	{
3142 		if (LogLevel > 0)
3143 			sm_syslog(LOG_ALERT, NOQID,
3144 				  "could not drop privileges: %s",
3145 				  sm_errstring(errno));
3146 		finis(false, true, EX_OSERR);
3147 		/* NOTREACHED */
3148 	}
3149 
3150 	sm_close_on_exec(STDERR_FILENO + 1, DtableSize);
3151 
3152 	/*
3153 	**  Need to allow signals before execve() to make them "harmless".
3154 	**  However, the default action can be "terminate", so it isn't
3155 	**  really harmless.  Setting signals to IGN will cause them to be
3156 	**  ignored in the new process to, so that isn't a good alternative.
3157 	*/
3158 
3159 	SM_NOOP_SIGNAL(SIGALRM, oalrm);
3160 	SM_NOOP_SIGNAL(SIGCHLD, ignore);
3161 	SM_NOOP_SIGNAL(SIGHUP, ignore);
3162 	SM_NOOP_SIGNAL(SIGINT, ignore);
3163 	SM_NOOP_SIGNAL(SIGPIPE, ignore);
3164 	SM_NOOP_SIGNAL(SIGTERM, ignore);
3165 #ifdef SIGUSR1
3166 	SM_NOOP_SIGNAL(SIGUSR1, ousr1);
3167 #endif /* SIGUSR1 */
3168 
3169 	/* Turn back on signals */
3170 	sm_allsignals(false);
3171 
3172 	(void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
3173 	save_errno = errno;
3174 
3175 	/* block signals again and restore needed signals */
3176 	sm_allsignals(true);
3177 
3178 	/* For finis() events */
3179 	(void) sm_signal(SIGALRM, oalrm);
3180 
3181 #ifdef SIGUSR1
3182 	/* For debugging finis() */
3183 	(void) sm_signal(SIGUSR1, ousr1);
3184 #endif /* SIGUSR1 */
3185 
3186 	errno = save_errno;
3187 	if (LogLevel > 0)
3188 		sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s",
3189 			  SaveArgv[0], sm_errstring(errno));
3190 	finis(false, true, EX_OSFILE);
3191 	/* NOTREACHED */
3192 }
3193 /*
3194 **  MYHOSTNAME -- return the name of this host.
3195 **
3196 **	Parameters:
3197 **		hostbuf -- a place to return the name of this host.
3198 **		size -- the size of hostbuf.
3199 **
3200 **	Returns:
3201 **		A list of aliases for this host.
3202 **
3203 **	Side Effects:
3204 **		Adds numeric codes to $=w.
3205 */
3206 
3207 struct hostent *
3208 myhostname(hostbuf, size)
3209 	char hostbuf[];
3210 	int size;
3211 {
3212 	register struct hostent *hp;
3213 
3214 	if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0')
3215 		(void) sm_strlcpy(hostbuf, "localhost", size);
3216 	hp = sm_gethostbyname(hostbuf, InetMode);
3217 #if NETINET && NETINET6
3218 	if (hp == NULL && InetMode == AF_INET6)
3219 	{
3220 		/*
3221 		**  It's possible that this IPv6 enabled machine doesn't
3222 		**  actually have any IPv6 interfaces and, therefore, no
3223 		**  IPv6 addresses.  Fall back to AF_INET.
3224 		*/
3225 
3226 		hp = sm_gethostbyname(hostbuf, AF_INET);
3227 	}
3228 #endif /* NETINET && NETINET6 */
3229 	if (hp == NULL)
3230 		return NULL;
3231 	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
3232 		(void) cleanstrcpy(hostbuf, hp->h_name, size);
3233 
3234 #if NETINFO
3235 	if (strchr(hostbuf, '.') == NULL)
3236 	{
3237 		char *domainname;
3238 
3239 		domainname = ni_propval("/locations", NULL, "resolver",
3240 					"domain", '\0');
3241 		if (domainname != NULL &&
3242 		    strlen(domainname) + strlen(hostbuf) + 1 < size)
3243 			(void) sm_strlcat2(hostbuf, ".", domainname, size);
3244 	}
3245 #endif /* NETINFO */
3246 
3247 	/*
3248 	**  If there is still no dot in the name, try looking for a
3249 	**  dotted alias.
3250 	*/
3251 
3252 	if (strchr(hostbuf, '.') == NULL)
3253 	{
3254 		char **ha;
3255 
3256 		for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
3257 		{
3258 			if (strchr(*ha, '.') != NULL)
3259 			{
3260 				(void) cleanstrcpy(hostbuf, *ha, size - 1);
3261 				hostbuf[size - 1] = '\0';
3262 				break;
3263 			}
3264 		}
3265 	}
3266 
3267 	/*
3268 	**  If _still_ no dot, wait for a while and try again -- it is
3269 	**  possible that some service is starting up.  This can result
3270 	**  in excessive delays if the system is badly configured, but
3271 	**  there really isn't a way around that, particularly given that
3272 	**  the config file hasn't been read at this point.
3273 	**  All in all, a bit of a mess.
3274 	*/
3275 
3276 	if (strchr(hostbuf, '.') == NULL &&
3277 	    !getcanonname(hostbuf, size, true, NULL))
3278 	{
3279 		sm_syslog(LOG_CRIT, NOQID,
3280 			  "My unqualified host name (%s) unknown; sleeping for retry",
3281 			  hostbuf);
3282 		message("My unqualified host name (%s) unknown; sleeping for retry",
3283 			hostbuf);
3284 		(void) sleep(60);
3285 		if (!getcanonname(hostbuf, size, true, NULL))
3286 		{
3287 			sm_syslog(LOG_ALERT, NOQID,
3288 				  "unable to qualify my own domain name (%s) -- using short name",
3289 				  hostbuf);
3290 			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
3291 				hostbuf);
3292 		}
3293 	}
3294 	return hp;
3295 }
3296 /*
3297 **  ADDRCMP -- compare two host addresses
3298 **
3299 **	Parameters:
3300 **		hp -- hostent structure for the first address
3301 **		ha -- actual first address
3302 **		sa -- second address
3303 **
3304 **	Returns:
3305 **		0 -- if ha and sa match
3306 **		else -- they don't match
3307 */
3308 
3309 static int
3310 addrcmp(hp, ha, sa)
3311 	struct hostent *hp;
3312 	char *ha;
3313 	SOCKADDR *sa;
3314 {
3315 #if NETINET6
3316 	unsigned char *a;
3317 #endif /* NETINET6 */
3318 
3319 	switch (sa->sa.sa_family)
3320 	{
3321 #if NETINET
3322 	  case AF_INET:
3323 		if (hp->h_addrtype == AF_INET)
3324 			return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
3325 		break;
3326 #endif /* NETINET */
3327 
3328 #if NETINET6
3329 	  case AF_INET6:
3330 		a = (unsigned char *) &sa->sin6.sin6_addr;
3331 
3332 		/* Straight binary comparison */
3333 		if (hp->h_addrtype == AF_INET6)
3334 			return memcmp(ha, a, IN6ADDRSZ);
3335 
3336 		/* If IPv4-mapped IPv6 address, compare the IPv4 section */
3337 		if (hp->h_addrtype == AF_INET &&
3338 		    IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
3339 			return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
3340 		break;
3341 #endif /* NETINET6 */
3342 	}
3343 	return -1;
3344 }
3345 /*
3346 **  GETAUTHINFO -- get the real host name associated with a file descriptor
3347 **
3348 **	Uses RFC1413 protocol to try to get info from the other end.
3349 **
3350 **	Parameters:
3351 **		fd -- the descriptor
3352 **		may_be_forged -- an outage that is set to true if the
3353 **			forward lookup of RealHostName does not match
3354 **			RealHostAddr; set to false if they do match.
3355 **
3356 **	Returns:
3357 **		The user@host information associated with this descriptor.
3358 */
3359 
3360 static jmp_buf	CtxAuthTimeout;
3361 
3362 static void
3363 authtimeout(ignore)
3364 	int ignore;
3365 {
3366 	/*
3367 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3368 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3369 	**	DOING.
3370 	*/
3371 
3372 	errno = ETIMEDOUT;
3373 	longjmp(CtxAuthTimeout, 1);
3374 }
3375 
3376 char *
3377 getauthinfo(fd, may_be_forged)
3378 	int fd;
3379 	bool *may_be_forged;
3380 {
3381 	unsigned short SM_NONVOLATILE port = 0;
3382 	SOCKADDR_LEN_T falen;
3383 	register char *volatile p = NULL;
3384 	SOCKADDR la;
3385 	SOCKADDR_LEN_T lalen;
3386 #ifndef NO_GETSERVBYNAME
3387 	register struct servent *sp;
3388 # if NETINET
3389 	static unsigned short port4 = 0;
3390 # endif /* NETINET */
3391 # if NETINET6
3392 	static unsigned short port6 = 0;
3393 # endif /* NETINET6 */
3394 #endif /* ! NO_GETSERVBYNAME */
3395 	volatile int s;
3396 	int i = 0;
3397 	size_t len;
3398 	SM_EVENT *ev;
3399 	int nleft;
3400 	struct hostent *hp;
3401 	char *ostype = NULL;
3402 	char **ha;
3403 	char ibuf[MAXNAME + 1];
3404 	static char hbuf[MAXNAME + MAXAUTHINFO + 11];
3405 
3406 	*may_be_forged = false;
3407 	falen = sizeof(RealHostAddr);
3408 	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
3409 	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
3410 	{
3411 		if (i < 0)
3412 		{
3413 			/*
3414 			**  ENOTSOCK is OK: bail on anything else, but reset
3415 			**  errno in this case, so a mis-report doesn't
3416 			**  happen later.
3417 			*/
3418 
3419 			if (errno != ENOTSOCK)
3420 				return NULL;
3421 			errno = 0;
3422 		}
3423 		(void) sm_strlcpyn(hbuf, sizeof(hbuf), 2, RealUserName,
3424 				   "@localhost");
3425 		if (tTd(9, 1))
3426 			sm_dprintf("getauthinfo: %s\n", hbuf);
3427 		return hbuf;
3428 	}
3429 
3430 	if (RealHostName == NULL)
3431 	{
3432 		/* translate that to a host name */
3433 		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
3434 		if (strlen(RealHostName) > MAXNAME)
3435 			RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */
3436 	}
3437 
3438 	/* cross check RealHostName with forward DNS lookup */
3439 	if (anynet_ntoa(&RealHostAddr)[0] != '[' &&
3440 	    RealHostName[0] != '[')
3441 	{
3442 		int family;
3443 
3444 		family = RealHostAddr.sa.sa_family;
3445 #if NETINET6 && NEEDSGETIPNODE
3446 		/*
3447 		**  If RealHostAddr is an IPv6 connection with an
3448 		**  IPv4-mapped address, we need RealHostName's IPv4
3449 		**  address(es) for addrcmp() to compare against
3450 		**  RealHostAddr.
3451 		**
3452 		**  Actually, we only need to do this for systems
3453 		**  which NEEDSGETIPNODE since the real getipnodebyname()
3454 		**  already does V4MAPPED address via the AI_V4MAPPEDCFG
3455 		**  flag.  A better fix to this problem is to add this
3456 		**  functionality to our stub getipnodebyname().
3457 		*/
3458 
3459 		if (family == AF_INET6 &&
3460 		    IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr))
3461 			family = AF_INET;
3462 #endif /* NETINET6 && NEEDSGETIPNODE */
3463 
3464 		/* try to match the reverse against the forward lookup */
3465 		hp = sm_gethostbyname(RealHostName, family);
3466 		if (hp == NULL)
3467 		{
3468 			/* XXX: Could be a temporary error on forward lookup */
3469 			*may_be_forged = true;
3470 		}
3471 		else
3472 		{
3473 			for (ha = hp->h_addr_list; *ha != NULL; ha++)
3474 			{
3475 				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
3476 					break;
3477 			}
3478 			*may_be_forged = *ha == NULL;
3479 #if NETINET6
3480 			freehostent(hp);
3481 			hp = NULL;
3482 #endif /* NETINET6 */
3483 		}
3484 	}
3485 
3486 	if (TimeOuts.to_ident == 0)
3487 		goto noident;
3488 
3489 	lalen = sizeof(la);
3490 	switch (RealHostAddr.sa.sa_family)
3491 	{
3492 #if NETINET
3493 	  case AF_INET:
3494 		if (getsockname(fd, &la.sa, &lalen) < 0 ||
3495 		    lalen <= 0 ||
3496 		    la.sa.sa_family != AF_INET)
3497 		{
3498 			/* no ident info */
3499 			goto noident;
3500 		}
3501 		port = RealHostAddr.sin.sin_port;
3502 
3503 		/* create ident query */
3504 		(void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n",
3505 				ntohs(RealHostAddr.sin.sin_port),
3506 				ntohs(la.sin.sin_port));
3507 
3508 		/* create local address */
3509 		la.sin.sin_port = 0;
3510 
3511 		/* create foreign address */
3512 # ifdef NO_GETSERVBYNAME
3513 		RealHostAddr.sin.sin_port = htons(113);
3514 # else /* NO_GETSERVBYNAME */
3515 
3516 		/*
3517 		**  getservbyname() consumes about 5% of the time
3518 		**  when receiving a small message (almost all of the time
3519 		**  spent in this routine).
3520 		**  Hence we store the port in a static variable
3521 		**  to save this time.
3522 		**  The portnumber shouldn't change very often...
3523 		**  This code makes the assumption that the port number
3524 		**  is not 0.
3525 		*/
3526 
3527 		if (port4 == 0)
3528 		{
3529 			sp = getservbyname("auth", "tcp");
3530 			if (sp != NULL)
3531 				port4 = sp->s_port;
3532 			else
3533 				port4 = htons(113);
3534 		}
3535 		RealHostAddr.sin.sin_port = port4;
3536 		break;
3537 # endif /* NO_GETSERVBYNAME */
3538 #endif /* NETINET */
3539 
3540 #if NETINET6
3541 	  case AF_INET6:
3542 		if (getsockname(fd, &la.sa, &lalen) < 0 ||
3543 		    lalen <= 0 ||
3544 		    la.sa.sa_family != AF_INET6)
3545 		{
3546 			/* no ident info */
3547 			goto noident;
3548 		}
3549 		port = RealHostAddr.sin6.sin6_port;
3550 
3551 		/* create ident query */
3552 		(void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n",
3553 				ntohs(RealHostAddr.sin6.sin6_port),
3554 				ntohs(la.sin6.sin6_port));
3555 
3556 		/* create local address */
3557 		la.sin6.sin6_port = 0;
3558 
3559 		/* create foreign address */
3560 # ifdef NO_GETSERVBYNAME
3561 		RealHostAddr.sin6.sin6_port = htons(113);
3562 # else /* NO_GETSERVBYNAME */
3563 		if (port6 == 0)
3564 		{
3565 			sp = getservbyname("auth", "tcp");
3566 			if (sp != NULL)
3567 				port6 = sp->s_port;
3568 			else
3569 				port6 = htons(113);
3570 		}
3571 		RealHostAddr.sin6.sin6_port = port6;
3572 		break;
3573 # endif /* NO_GETSERVBYNAME */
3574 #endif /* NETINET6 */
3575 	  default:
3576 		/* no ident info */
3577 		goto noident;
3578 	}
3579 
3580 	s = -1;
3581 	if (setjmp(CtxAuthTimeout) != 0)
3582 	{
3583 		if (s >= 0)
3584 			(void) close(s);
3585 		goto noident;
3586 	}
3587 
3588 	/* put a timeout around the whole thing */
3589 	ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0);
3590 
3591 	/* connect to foreign IDENT server using same address as SMTP socket */
3592 	s = socket(la.sa.sa_family, SOCK_STREAM, 0);
3593 	if (s < 0)
3594 	{
3595 		sm_clrevent(ev);
3596 		goto noident;
3597 	}
3598 	if (bind(s, &la.sa, lalen) < 0 ||
3599 	    connect(s, &RealHostAddr.sa, lalen) < 0)
3600 		goto closeident;
3601 
3602 	if (tTd(9, 10))
3603 		sm_dprintf("getauthinfo: sent %s", ibuf);
3604 
3605 	/* send query */
3606 	if (write(s, ibuf, strlen(ibuf)) < 0)
3607 		goto closeident;
3608 
3609 	/* get result */
3610 	p = &ibuf[0];
3611 	nleft = sizeof(ibuf) - 1;
3612 	while ((i = read(s, p, nleft)) > 0)
3613 	{
3614 		char *s;
3615 
3616 		p += i;
3617 		nleft -= i;
3618 		*p = '\0';
3619 		if ((s = strchr(ibuf, '\n')) != NULL)
3620 		{
3621 			if (p > s + 1)
3622 			{
3623 				p = s + 1;
3624 				*p = '\0';
3625 			}
3626 			break;
3627 		}
3628 		if (nleft <= 0)
3629 			break;
3630 	}
3631 	(void) close(s);
3632 	sm_clrevent(ev);
3633 	if (i < 0 || p == &ibuf[0])
3634 		goto noident;
3635 
3636 	if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r')
3637 		p--;
3638 	*++p = '\0';
3639 
3640 	if (tTd(9, 3))
3641 		sm_dprintf("getauthinfo:  got %s\n", ibuf);
3642 
3643 	/* parse result */
3644 	p = strchr(ibuf, ':');
3645 	if (p == NULL)
3646 	{
3647 		/* malformed response */
3648 		goto noident;
3649 	}
3650 	while (isascii(*++p) && isspace(*p))
3651 		continue;
3652 	if (sm_strncasecmp(p, "userid", 6) != 0)
3653 	{
3654 		/* presumably an error string */
3655 		goto noident;
3656 	}
3657 	p += 6;
3658 	while (isascii(*p) && isspace(*p))
3659 		p++;
3660 	if (*p++ != ':')
3661 	{
3662 		/* either useridxx or malformed response */
3663 		goto noident;
3664 	}
3665 
3666 	/* p now points to the OSTYPE field */
3667 	while (isascii(*p) && isspace(*p))
3668 		p++;
3669 	ostype = p;
3670 	p = strchr(p, ':');
3671 	if (p == NULL)
3672 	{
3673 		/* malformed response */
3674 		goto noident;
3675 	}
3676 	else
3677 	{
3678 		char *charset;
3679 
3680 		*p = '\0';
3681 		charset = strchr(ostype, ',');
3682 		if (charset != NULL)
3683 			*charset = '\0';
3684 	}
3685 
3686 	/* 1413 says don't do this -- but it's broken otherwise */
3687 	while (isascii(*++p) && isspace(*p))
3688 		continue;
3689 
3690 	/* p now points to the authenticated name -- copy carefully */
3691 	if (sm_strncasecmp(ostype, "other", 5) == 0 &&
3692 	    (ostype[5] == ' ' || ostype[5] == '\0'))
3693 	{
3694 		(void) sm_strlcpy(hbuf, "IDENT:", sizeof(hbuf));
3695 		cleanstrcpy(&hbuf[6], p, MAXAUTHINFO);
3696 	}
3697 	else
3698 		cleanstrcpy(hbuf, p, MAXAUTHINFO);
3699 	len = strlen(hbuf);
3700 	(void) sm_strlcpyn(&hbuf[len], sizeof(hbuf) - len, 2, "@",
3701 			   RealHostName == NULL ? "localhost" : RealHostName);
3702 	goto postident;
3703 
3704 closeident:
3705 	(void) close(s);
3706 	sm_clrevent(ev);
3707 
3708 noident:
3709 	/* put back the original incoming port */
3710 	switch (RealHostAddr.sa.sa_family)
3711 	{
3712 #if NETINET
3713 	  case AF_INET:
3714 		if (port > 0)
3715 			RealHostAddr.sin.sin_port = port;
3716 		break;
3717 #endif /* NETINET */
3718 
3719 #if NETINET6
3720 	  case AF_INET6:
3721 		if (port > 0)
3722 			RealHostAddr.sin6.sin6_port = port;
3723 		break;
3724 #endif /* NETINET6 */
3725 	}
3726 
3727 	if (RealHostName == NULL)
3728 	{
3729 		if (tTd(9, 1))
3730 			sm_dprintf("getauthinfo: NULL\n");
3731 		return NULL;
3732 	}
3733 	(void) sm_strlcpy(hbuf, RealHostName, sizeof(hbuf));
3734 
3735 postident:
3736 #if IP_SRCROUTE
3737 # ifndef GET_IPOPT_DST
3738 #  define GET_IPOPT_DST(dst)	(dst)
3739 # endif /* ! GET_IPOPT_DST */
3740 	/*
3741 	**  Extract IP source routing information.
3742 	**
3743 	**	Format of output for a connection from site a through b
3744 	**	through c to d:
3745 	**		loose:      @site-c@site-b:site-a
3746 	**		strict:	   !@site-c@site-b:site-a
3747 	**
3748 	**	o - pointer within ipopt_list structure.
3749 	**	q - pointer within ls/ss rr route data
3750 	**	p - pointer to hbuf
3751 	*/
3752 
3753 	if (RealHostAddr.sa.sa_family == AF_INET)
3754 	{
3755 		SOCKOPT_LEN_T ipoptlen;
3756 		int j;
3757 		unsigned char *q;
3758 		unsigned char *o;
3759 		int l;
3760 		struct IPOPTION ipopt;
3761 
3762 		ipoptlen = sizeof(ipopt);
3763 		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
3764 			       (char *) &ipopt, &ipoptlen) < 0)
3765 			goto noipsr;
3766 		if (ipoptlen == 0)
3767 			goto noipsr;
3768 		o = (unsigned char *) ipopt.IP_LIST;
3769 		while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen)
3770 		{
3771 			switch (*o)
3772 			{
3773 			  case IPOPT_EOL:
3774 				o = NULL;
3775 				break;
3776 
3777 			  case IPOPT_NOP:
3778 				o++;
3779 				break;
3780 
3781 			  case IPOPT_SSRR:
3782 			  case IPOPT_LSRR:
3783 				/*
3784 				**  Source routing.
3785 				**	o[0] is the option type (loose/strict).
3786 				**	o[1] is the length of this option,
3787 				**		including option type and
3788 				**		length.
3789 				**	o[2] is the pointer into the route
3790 				**		data.
3791 				**	o[3] begins the route data.
3792 				*/
3793 
3794 				p = &hbuf[strlen(hbuf)];
3795 				l = sizeof(hbuf) - (hbuf - p) - 6;
3796 				(void) sm_snprintf(p, SPACELEFT(hbuf, p),
3797 					" [%s@%.*s",
3798 					*o == IPOPT_SSRR ? "!" : "",
3799 					l > 240 ? 120 : l / 2,
3800 					inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
3801 				i = strlen(p);
3802 				p += i;
3803 				l -= strlen(p);
3804 
3805 				j = o[1] / sizeof(struct in_addr) - 1;
3806 
3807 				/* q skips length and router pointer to data */
3808 				q = &o[3];
3809 				for ( ; j >= 0; j--)
3810 				{
3811 					struct in_addr addr;
3812 
3813 					memcpy(&addr, q, sizeof(addr));
3814 					(void) sm_snprintf(p,
3815 						SPACELEFT(hbuf, p),
3816 						"%c%.*s",
3817 						j != 0 ? '@' : ':',
3818 						l > 240 ? 120 :
3819 							j == 0 ? l : l / 2,
3820 						inet_ntoa(addr));
3821 					i = strlen(p);
3822 					p += i;
3823 					l -= i + 1;
3824 					q += sizeof(struct in_addr);
3825 				}
3826 				o += o[1];
3827 				break;
3828 
3829 			  default:
3830 				/* Skip over option */
3831 				o += o[1];
3832 				break;
3833 			}
3834 		}
3835 		(void) sm_snprintf(p, SPACELEFT(hbuf, p), "]");
3836 		goto postipsr;
3837 	}
3838 
3839 noipsr:
3840 #endif /* IP_SRCROUTE */
3841 	if (RealHostName != NULL && RealHostName[0] != '[')
3842 	{
3843 		p = &hbuf[strlen(hbuf)];
3844 		(void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
3845 				   anynet_ntoa(&RealHostAddr));
3846 	}
3847 	if (*may_be_forged)
3848 	{
3849 		p = &hbuf[strlen(hbuf)];
3850 		(void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p));
3851 		macdefine(&BlankEnvelope.e_macro, A_PERM,
3852 			  macid("{client_resolve}"), "FORGED");
3853 	}
3854 
3855 #if IP_SRCROUTE
3856 postipsr:
3857 #endif /* IP_SRCROUTE */
3858 
3859 	/* put back the original incoming port */
3860 	switch (RealHostAddr.sa.sa_family)
3861 	{
3862 #if NETINET
3863 	  case AF_INET:
3864 		if (port > 0)
3865 			RealHostAddr.sin.sin_port = port;
3866 		break;
3867 #endif /* NETINET */
3868 
3869 #if NETINET6
3870 	  case AF_INET6:
3871 		if (port > 0)
3872 			RealHostAddr.sin6.sin6_port = port;
3873 		break;
3874 #endif /* NETINET6 */
3875 	}
3876 
3877 	if (tTd(9, 1))
3878 		sm_dprintf("getauthinfo: %s\n", hbuf);
3879 	return hbuf;
3880 }
3881 /*
3882 **  HOST_MAP_LOOKUP -- turn a hostname into canonical form
3883 **
3884 **	Parameters:
3885 **		map -- a pointer to this map.
3886 **		name -- the (presumably unqualified) hostname.
3887 **		av -- unused -- for compatibility with other mapping
3888 **			functions.
3889 **		statp -- an exit status (out parameter) -- set to
3890 **			EX_TEMPFAIL if the name server is unavailable.
3891 **
3892 **	Returns:
3893 **		The mapping, if found.
3894 **		NULL if no mapping found.
3895 **
3896 **	Side Effects:
3897 **		Looks up the host specified in hbuf.  If it is not
3898 **		the canonical name for that host, return the canonical
3899 **		name (unless MF_MATCHONLY is set, which will cause the
3900 **		status only to be returned).
3901 */
3902 
3903 char *
3904 host_map_lookup(map, name, av, statp)
3905 	MAP *map;
3906 	char *name;
3907 	char **av;
3908 	int *statp;
3909 {
3910 	register struct hostent *hp;
3911 #if NETINET
3912 	struct in_addr in_addr;
3913 #endif /* NETINET */
3914 #if NETINET6
3915 	struct in6_addr in6_addr;
3916 #endif /* NETINET6 */
3917 	char *cp, *ans = NULL;
3918 	register STAB *s;
3919 	time_t now;
3920 #if NAMED_BIND
3921 	time_t SM_NONVOLATILE retrans = 0;
3922 	int SM_NONVOLATILE retry = 0;
3923 #endif /* NAMED_BIND */
3924 	char hbuf[MAXNAME + 1];
3925 
3926 	/*
3927 	**  See if we have already looked up this name.  If so, just
3928 	**  return it (unless expired).
3929 	*/
3930 
3931 	now = curtime();
3932 	s = stab(name, ST_NAMECANON, ST_ENTER);
3933 	if (bitset(NCF_VALID, s->s_namecanon.nc_flags) &&
3934 	    s->s_namecanon.nc_exp >= now)
3935 	{
3936 		if (tTd(9, 1))
3937 			sm_dprintf("host_map_lookup(%s) => CACHE %s\n",
3938 				    name,
3939 				    s->s_namecanon.nc_cname == NULL
3940 					? "NULL"
3941 					: s->s_namecanon.nc_cname);
3942 		errno = s->s_namecanon.nc_errno;
3943 		SM_SET_H_ERRNO(s->s_namecanon.nc_herrno);
3944 		*statp = s->s_namecanon.nc_stat;
3945 		if (*statp == EX_TEMPFAIL)
3946 		{
3947 			CurEnv->e_status = "4.4.3";
3948 			message("851 %s: Name server timeout",
3949 				shortenstring(name, 33));
3950 		}
3951 		if (*statp != EX_OK)
3952 			return NULL;
3953 		if (s->s_namecanon.nc_cname == NULL)
3954 		{
3955 			syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d",
3956 			       name,
3957 			       s->s_namecanon.nc_errno,
3958 			       s->s_namecanon.nc_herrno);
3959 			return NULL;
3960 		}
3961 		if (bitset(MF_MATCHONLY, map->map_mflags))
3962 			cp = map_rewrite(map, name, strlen(name), NULL);
3963 		else
3964 			cp = map_rewrite(map,
3965 					 s->s_namecanon.nc_cname,
3966 					 strlen(s->s_namecanon.nc_cname),
3967 					 av);
3968 		return cp;
3969 	}
3970 
3971 	/*
3972 	**  If we are running without a regular network connection (usually
3973 	**  dial-on-demand) and we are just queueing, we want to avoid DNS
3974 	**  lookups because those could try to connect to a server.
3975 	*/
3976 
3977 	if (CurEnv->e_sendmode == SM_DEFER &&
3978 	    bitset(MF_DEFER, map->map_mflags))
3979 	{
3980 		if (tTd(9, 1))
3981 			sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name);
3982 		*statp = EX_TEMPFAIL;
3983 		return NULL;
3984 	}
3985 
3986 	/*
3987 	**  If first character is a bracket, then it is an address
3988 	**  lookup.  Address is copied into a temporary buffer to
3989 	**  strip the brackets and to preserve name if address is
3990 	**  unknown.
3991 	*/
3992 
3993 	if (tTd(9, 1))
3994 		sm_dprintf("host_map_lookup(%s) => ", name);
3995 #if NAMED_BIND
3996 	if (map->map_timeout > 0)
3997 	{
3998 		retrans = _res.retrans;
3999 		_res.retrans = map->map_timeout;
4000 	}
4001 	if (map->map_retry > 0)
4002 	{
4003 		retry = _res.retry;
4004 		_res.retry = map->map_retry;
4005 	}
4006 #endif /* NAMED_BIND */
4007 
4008 	/* set default TTL */
4009 	s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL;
4010 	if (*name != '[')
4011 	{
4012 		int ttl;
4013 
4014 		(void) sm_strlcpy(hbuf, name, sizeof(hbuf));
4015 		if (getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl))
4016 		{
4017 			ans = hbuf;
4018 			if (ttl > 0)
4019 				s->s_namecanon.nc_exp = now + SM_MIN(ttl,
4020 								SM_DEFAULT_TTL);
4021 		}
4022 	}
4023 	else
4024 	{
4025 		if ((cp = strchr(name, ']')) == NULL)
4026 		{
4027 			if (tTd(9, 1))
4028 				sm_dprintf("FAILED\n");
4029 			return NULL;
4030 		}
4031 		*cp = '\0';
4032 
4033 		hp = NULL;
4034 #if NETINET
4035 		if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
4036 			hp = sm_gethostbyaddr((char *)&in_addr,
4037 					      INADDRSZ, AF_INET);
4038 #endif /* NETINET */
4039 #if NETINET6
4040 		if (hp == NULL &&
4041 		    anynet_pton(AF_INET6, &name[1], &in6_addr) == 1)
4042 			hp = sm_gethostbyaddr((char *)&in6_addr,
4043 					      IN6ADDRSZ, AF_INET6);
4044 #endif /* NETINET6 */
4045 		*cp = ']';
4046 
4047 		if (hp != NULL)
4048 		{
4049 			/* found a match -- copy out */
4050 			ans = denlstring((char *) hp->h_name, true, true);
4051 #if NETINET6
4052 			if (ans == hp->h_name)
4053 			{
4054 				static char n[MAXNAME + 1];
4055 
4056 				/* hp->h_name is about to disappear */
4057 				(void) sm_strlcpy(n, ans, sizeof(n));
4058 				ans = n;
4059 			}
4060 			freehostent(hp);
4061 			hp = NULL;
4062 #endif /* NETINET6 */
4063 		}
4064 	}
4065 #if NAMED_BIND
4066 	if (map->map_timeout > 0)
4067 		_res.retrans = retrans;
4068 	if (map->map_retry > 0)
4069 		_res.retry = retry;
4070 #endif /* NAMED_BIND */
4071 
4072 	s->s_namecanon.nc_flags |= NCF_VALID;	/* will be soon */
4073 
4074 	/* Found an answer */
4075 	if (ans != NULL)
4076 	{
4077 		s->s_namecanon.nc_stat = *statp = EX_OK;
4078 		if (s->s_namecanon.nc_cname != NULL)
4079 			sm_free(s->s_namecanon.nc_cname);
4080 		s->s_namecanon.nc_cname = sm_strdup_x(ans);
4081 		if (bitset(MF_MATCHONLY, map->map_mflags))
4082 			cp = map_rewrite(map, name, strlen(name), NULL);
4083 		else
4084 			cp = map_rewrite(map, ans, strlen(ans), av);
4085 		if (tTd(9, 1))
4086 			sm_dprintf("FOUND %s\n", ans);
4087 		return cp;
4088 	}
4089 
4090 
4091 	/* No match found */
4092 	s->s_namecanon.nc_errno = errno;
4093 #if NAMED_BIND
4094 	s->s_namecanon.nc_herrno = h_errno;
4095 	if (tTd(9, 1))
4096 		sm_dprintf("FAIL (%d)\n", h_errno);
4097 	switch (h_errno)
4098 	{
4099 	  case TRY_AGAIN:
4100 		if (UseNameServer)
4101 		{
4102 			CurEnv->e_status = "4.4.3";
4103 			message("851 %s: Name server timeout",
4104 				shortenstring(name, 33));
4105 		}
4106 		*statp = EX_TEMPFAIL;
4107 		break;
4108 
4109 	  case HOST_NOT_FOUND:
4110 	  case NO_DATA:
4111 		*statp = EX_NOHOST;
4112 		break;
4113 
4114 	  case NO_RECOVERY:
4115 		*statp = EX_SOFTWARE;
4116 		break;
4117 
4118 	  default:
4119 		*statp = EX_UNAVAILABLE;
4120 		break;
4121 	}
4122 #else /* NAMED_BIND */
4123 	if (tTd(9, 1))
4124 		sm_dprintf("FAIL\n");
4125 	*statp = EX_NOHOST;
4126 #endif /* NAMED_BIND */
4127 	s->s_namecanon.nc_stat = *statp;
4128 	return NULL;
4129 }
4130 /*
4131 **  HOST_MAP_INIT -- initialize host class structures
4132 **
4133 **	Parameters:
4134 **		map -- a pointer to this map.
4135 **		args -- argument string.
4136 **
4137 **	Returns:
4138 **		true.
4139 */
4140 
4141 bool
4142 host_map_init(map, args)
4143 	MAP *map;
4144 	char *args;
4145 {
4146 	register char *p = args;
4147 
4148 	for (;;)
4149 	{
4150 		while (isascii(*p) && isspace(*p))
4151 			p++;
4152 		if (*p != '-')
4153 			break;
4154 		switch (*++p)
4155 		{
4156 		  case 'a':
4157 			map->map_app = ++p;
4158 			break;
4159 
4160 		  case 'T':
4161 			map->map_tapp = ++p;
4162 			break;
4163 
4164 		  case 'm':
4165 			map->map_mflags |= MF_MATCHONLY;
4166 			break;
4167 
4168 		  case 't':
4169 			map->map_mflags |= MF_NODEFER;
4170 			break;
4171 
4172 		  case 'S':	/* only for consistency */
4173 			map->map_spacesub = *++p;
4174 			break;
4175 
4176 		  case 'D':
4177 			map->map_mflags |= MF_DEFER;
4178 			break;
4179 
4180 		  case 'd':
4181 			{
4182 				char *h;
4183 
4184 				while (isascii(*++p) && isspace(*p))
4185 					continue;
4186 				h = strchr(p, ' ');
4187 				if (h != NULL)
4188 					*h = '\0';
4189 				map->map_timeout = convtime(p, 's');
4190 				if (h != NULL)
4191 					*h = ' ';
4192 			}
4193 			break;
4194 
4195 		  case 'r':
4196 			while (isascii(*++p) && isspace(*p))
4197 				continue;
4198 			map->map_retry = atoi(p);
4199 			break;
4200 		}
4201 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4202 			p++;
4203 		if (*p != '\0')
4204 			*p++ = '\0';
4205 	}
4206 	if (map->map_app != NULL)
4207 		map->map_app = newstr(map->map_app);
4208 	if (map->map_tapp != NULL)
4209 		map->map_tapp = newstr(map->map_tapp);
4210 	return true;
4211 }
4212 
4213 #if NETINET6
4214 /*
4215 **  ANYNET_NTOP -- convert an IPv6 network address to printable form.
4216 **
4217 **	Parameters:
4218 **		s6a -- a pointer to an in6_addr structure.
4219 **		dst -- buffer to store result in
4220 **		dst_len -- size of dst buffer
4221 **
4222 **	Returns:
4223 **		A printable version of that structure.
4224 */
4225 
4226 char *
4227 anynet_ntop(s6a, dst, dst_len)
4228 	struct in6_addr *s6a;
4229 	char *dst;
4230 	size_t dst_len;
4231 {
4232 	register char *ap;
4233 
4234 	if (IN6_IS_ADDR_V4MAPPED(s6a))
4235 		ap = (char *) inet_ntop(AF_INET,
4236 					&s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
4237 					dst, dst_len);
4238 	else
4239 	{
4240 		char *d;
4241 		size_t sz;
4242 
4243 		/* Save pointer to beginning of string */
4244 		d = dst;
4245 
4246 		/* Add IPv6: protocol tag */
4247 		sz = sm_strlcpy(dst, "IPv6:", dst_len);
4248 		if (sz >= dst_len)
4249 			return NULL;
4250 		dst += sz;
4251 		dst_len -= sz;
4252 		ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
4253 
4254 		/* Restore pointer to beginning of string */
4255 		if (ap != NULL)
4256 			ap = d;
4257 	}
4258 	return ap;
4259 }
4260 
4261 /*
4262 **  ANYNET_PTON -- convert printed form to network address.
4263 **
4264 **	Wrapper for inet_pton() which handles IPv6: labels.
4265 **
4266 **	Parameters:
4267 **		family -- address family
4268 **		src -- string
4269 **		dst -- destination address structure
4270 **
4271 **	Returns:
4272 **		1 if the address was valid
4273 **		0 if the address wasn't parseable
4274 **		-1 if error
4275 */
4276 
4277 int
4278 anynet_pton(family, src, dst)
4279 	int family;
4280 	const char *src;
4281 	void *dst;
4282 {
4283 	if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0)
4284 		src += 5;
4285 	return inet_pton(family, src, dst);
4286 }
4287 #endif /* NETINET6 */
4288 /*
4289 **  ANYNET_NTOA -- convert a network address to printable form.
4290 **
4291 **	Parameters:
4292 **		sap -- a pointer to a sockaddr structure.
4293 **
4294 **	Returns:
4295 **		A printable version of that sockaddr.
4296 */
4297 
4298 #ifdef USE_SOCK_STREAM
4299 
4300 # if NETLINK
4301 #  include <net/if_dl.h>
4302 # endif /* NETLINK */
4303 
4304 char *
4305 anynet_ntoa(sap)
4306 	register SOCKADDR *sap;
4307 {
4308 	register char *bp;
4309 	register char *ap;
4310 	int l;
4311 	static char buf[100];
4312 
4313 	/* check for null/zero family */
4314 	if (sap == NULL)
4315 		return "NULLADDR";
4316 	if (sap->sa.sa_family == 0)
4317 		return "0";
4318 
4319 	switch (sap->sa.sa_family)
4320 	{
4321 # if NETUNIX
4322 	  case AF_UNIX:
4323 		if (sap->sunix.sun_path[0] != '\0')
4324 			(void) sm_snprintf(buf, sizeof(buf), "[UNIX: %.64s]",
4325 					   sap->sunix.sun_path);
4326 		else
4327 			(void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof(buf));
4328 		return buf;
4329 # endif /* NETUNIX */
4330 
4331 # if NETINET
4332 	  case AF_INET:
4333 		return (char *) inet_ntoa(sap->sin.sin_addr);
4334 # endif /* NETINET */
4335 
4336 # if NETINET6
4337 	  case AF_INET6:
4338 		ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof(buf));
4339 		if (ap != NULL)
4340 			return ap;
4341 		break;
4342 # endif /* NETINET6 */
4343 
4344 # if NETLINK
4345 	  case AF_LINK:
4346 		(void) sm_snprintf(buf, sizeof(buf), "[LINK: %s]",
4347 				   link_ntoa((struct sockaddr_dl *) &sap->sa));
4348 		return buf;
4349 # endif /* NETLINK */
4350 	  default:
4351 		/* this case is needed when nothing is #defined */
4352 		/* in order to keep the switch syntactically correct */
4353 		break;
4354 	}
4355 
4356 	/* unknown family -- just dump bytes */
4357 	(void) sm_snprintf(buf, sizeof(buf), "Family %d: ", sap->sa.sa_family);
4358 	bp = &buf[strlen(buf)];
4359 	ap = sap->sa.sa_data;
4360 	for (l = sizeof(sap->sa.sa_data); --l >= 0; )
4361 	{
4362 		(void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:",
4363 				   *ap++ & 0377);
4364 		bp += 3;
4365 	}
4366 	*--bp = '\0';
4367 	return buf;
4368 }
4369 /*
4370 **  HOSTNAMEBYANYADDR -- return name of host based on address
4371 **
4372 **	Parameters:
4373 **		sap -- SOCKADDR pointer
4374 **
4375 **	Returns:
4376 **		text representation of host name.
4377 **
4378 **	Side Effects:
4379 **		none.
4380 */
4381 
4382 char *
4383 hostnamebyanyaddr(sap)
4384 	register SOCKADDR *sap;
4385 {
4386 	register struct hostent *hp;
4387 # if NAMED_BIND
4388 	int saveretry;
4389 # endif /* NAMED_BIND */
4390 # if NETINET6
4391 	struct in6_addr in6_addr;
4392 # endif /* NETINET6 */
4393 
4394 # if NAMED_BIND
4395 	/* shorten name server timeout to avoid higher level timeouts */
4396 	saveretry = _res.retry;
4397 	if (_res.retry * _res.retrans > 20)
4398 		_res.retry = 20 / _res.retrans;
4399 # endif /* NAMED_BIND */
4400 
4401 	switch (sap->sa.sa_family)
4402 	{
4403 # if NETINET
4404 	  case AF_INET:
4405 		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
4406 				      INADDRSZ, AF_INET);
4407 		break;
4408 # endif /* NETINET */
4409 
4410 # if NETINET6
4411 	  case AF_INET6:
4412 		hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
4413 				      IN6ADDRSZ, AF_INET6);
4414 		break;
4415 # endif /* NETINET6 */
4416 
4417 # if NETISO
4418 	  case AF_ISO:
4419 		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
4420 				      sizeof(sap->siso.siso_addr), AF_ISO);
4421 		break;
4422 # endif /* NETISO */
4423 
4424 # if NETUNIX
4425 	  case AF_UNIX:
4426 		hp = NULL;
4427 		break;
4428 # endif /* NETUNIX */
4429 
4430 	  default:
4431 		hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof(sap->sa.sa_data),
4432 				      sap->sa.sa_family);
4433 		break;
4434 	}
4435 
4436 # if NAMED_BIND
4437 	_res.retry = saveretry;
4438 # endif /* NAMED_BIND */
4439 
4440 # if NETINET || NETINET6
4441 	if (hp != NULL && hp->h_name[0] != '['
4442 #  if NETINET6
4443 	    && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1
4444 #  endif /* NETINET6 */
4445 #  if NETINET
4446 	    && inet_addr(hp->h_name) == INADDR_NONE
4447 #  endif /* NETINET */
4448 	    )
4449 	{
4450 		char *name;
4451 
4452 		name = denlstring((char *) hp->h_name, true, true);
4453 #  if NETINET6
4454 		if (name == hp->h_name)
4455 		{
4456 			static char n[MAXNAME + 1];
4457 
4458 			/* Copy the string, hp->h_name is about to disappear */
4459 			(void) sm_strlcpy(n, name, sizeof(n));
4460 			name = n;
4461 		}
4462 		freehostent(hp);
4463 #  endif /* NETINET6 */
4464 		return name;
4465 	}
4466 # endif /* NETINET || NETINET6 */
4467 
4468 # if NETINET6
4469 	if (hp != NULL)
4470 	{
4471 		freehostent(hp);
4472 		hp = NULL;
4473 	}
4474 # endif /* NETINET6 */
4475 
4476 # if NETUNIX
4477 	if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
4478 		return "localhost";
4479 # endif /* NETUNIX */
4480 	{
4481 		static char buf[203];
4482 
4483 		(void) sm_snprintf(buf, sizeof(buf), "[%.200s]",
4484 				   anynet_ntoa(sap));
4485 		return buf;
4486 	}
4487 }
4488 #endif /* USE_SOCK_STREAM */
4489