xref: /freebsd/contrib/sendmail/src/daemon.c (revision 04c9749ff0148ec8f73b150cec8bc2c094a5d31a)
1 /*
2  * Copyright (c) 1998-2000 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 #include <sendmail.h>
15 
16 
17 #ifndef lint
18 # ifdef DAEMON
19 static char id[] = "@(#)$Id: daemon.c,v 8.401.4.14 2000/07/14 04:15:00 gshapiro Exp $ (with daemon mode)";
20 # else /* DAEMON */
21 static char id[] = "@(#)$Id: daemon.c,v 8.401.4.14 2000/07/14 04:15:00 gshapiro Exp $ (without daemon mode)";
22 # endif /* DAEMON */
23 #endif /* ! lint */
24 
25 #if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
26 # define USE_SOCK_STREAM	1
27 #endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
28 
29 #if DAEMON || defined(USE_SOCK_STREAM)
30 # if NETINET || NETINET6
31 #  include <arpa/inet.h>
32 # endif /* NETINET || NETINET6 */
33 # if NAMED_BIND
34 #  ifndef NO_DATA
35 #   define NO_DATA	NO_ADDRESS
36 #  endif /* ! NO_DATA */
37 # endif /* NAMED_BIND */
38 #endif /* DAEMON || defined(USE_SOCK_STREAM) */
39 
40 #if DAEMON
41 
42 # include <sys/time.h>
43 
44 # if IP_SRCROUTE && NETINET
45 #  include <netinet/in_systm.h>
46 #  include <netinet/ip.h>
47 #  if HAS_IN_H
48 #   include <netinet/in.h>
49 #   ifndef IPOPTION
50 #    define IPOPTION	ip_opts
51 #    define IP_LIST	ip_opts
52 #    define IP_DST	ip_dst
53 #   endif /* ! IPOPTION */
54 #  else /* HAS_IN_H */
55 #   include <netinet/ip_var.h>
56 #   ifndef IPOPTION
57 #    define IPOPTION	ipoption
58 #    define IP_LIST	ipopt_list
59 #    define IP_DST	ipopt_dst
60 #   endif /* ! IPOPTION */
61 #  endif /* HAS_IN_H */
62 # endif /* IP_SRCROUTE && NETINET */
63 
64 /* structure to describe a daemon */
65 struct daemon
66 {
67 	int		d_socket;	/* fd for socket */
68 	SOCKADDR	d_addr;		/* socket for incoming */
69 	u_short		d_port;		/* port number */
70 	int		d_listenqueue;	/* size of listen queue */
71 	int		d_tcprcvbufsize;	/* size of TCP receive buffer */
72 	int		d_tcpsndbufsize;	/* size of TCP send buffer */
73 	time_t		d_refuse_connections_until;
74 	bool		d_firsttime;
75 	int		d_socksize;
76 	BITMAP256	d_flags;	/* flags; see sendmail.h */
77 	char		*d_mflags;	/* flags for use in macro */
78 	char		*d_name;	/* user-supplied name */
79 };
80 
81 typedef struct daemon DAEMON_T;
82 
83 static void	connecttimeout __P((void));
84 static int	opendaemonsocket __P((struct daemon *, bool));
85 static u_short	setupdaemon __P((SOCKADDR *));
86 
87 /*
88 **  DAEMON.C -- routines to use when running as a daemon.
89 **
90 **	This entire file is highly dependent on the 4.2 BSD
91 **	interprocess communication primitives.  No attempt has
92 **	been made to make this file portable to Version 7,
93 **	Version 6, MPX files, etc.  If you should try such a
94 **	thing yourself, I recommend chucking the entire file
95 **	and starting from scratch.  Basic semantics are:
96 **
97 **	getrequests(e)
98 **		Opens a port and initiates a connection.
99 **		Returns in a child.  Must set InChannel and
100 **		OutChannel appropriately.
101 **	clrdaemon()
102 **		Close any open files associated with getting
103 **		the connection; this is used when running the queue,
104 **		etc., to avoid having extra file descriptors during
105 **		the queue run and to avoid confusing the network
106 **		code (if it cares).
107 **	makeconnection(host, port, outfile, infile, e)
108 **		Make a connection to the named host on the given
109 **		port.  Set *outfile and *infile to the files
110 **		appropriate for communication.  Returns zero on
111 **		success, else an exit status describing the
112 **		error.
113 **	host_map_lookup(map, hbuf, avp, pstat)
114 **		Convert the entry in hbuf into a canonical form.
115 */
116 
117 static DAEMON_T	Daemons[MAXDAEMONS];
118 static int	ndaemons = 0;			/* actual number of daemons */
119 
120 /* options for client */
121 static int	TcpRcvBufferSize = 0;	/* size of TCP receive buffer */
122 static int	TcpSndBufferSize = 0;	/* size of TCP send buffer */
123 
124 /*
125 **  GETREQUESTS -- open mail IPC port and get requests.
126 **
127 **	Parameters:
128 **		e -- the current envelope.
129 **
130 **	Returns:
131 **		pointer to flags.
132 **
133 **	Side Effects:
134 **		Waits until some interesting activity occurs.  When
135 **		it does, a child is created to process it, and the
136 **		parent waits for completion.  Return from this
137 **		routine is always in the child.  The file pointers
138 **		"InChannel" and "OutChannel" should be set to point
139 **		to the communication channel.
140 */
141 
142 BITMAP256 *
143 getrequests(e)
144 	ENVELOPE *e;
145 {
146 	int t;
147 	time_t last_disk_space_check = 0;
148 	int idx, curdaemon = -1;
149 	int i, olddaemon = 0;
150 # if XDEBUG
151 	bool j_has_dot;
152 # endif /* XDEBUG */
153 	char status[MAXLINE];
154 	SOCKADDR sa;
155 	SOCKADDR_LEN_T len = sizeof sa;
156 # if NETUNIX
157 	extern int ControlSocket;
158 # endif /* NETUNIX */
159 	extern ENVELOPE BlankEnvelope;
160 
161 #define D(x,idx)	x[idx]
162 
163 
164 	for (idx = 0; idx < ndaemons; idx++)
165 	{
166 		Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
167 		Daemons[idx].d_firsttime = TRUE;
168 		Daemons[idx].d_refuse_connections_until = (time_t) 0;
169 	}
170 	/*
171 	**  Try to actually open the connection.
172 	*/
173 
174 	if (tTd(15, 1))
175 	{
176 		for (idx = 0; idx < ndaemons; idx++)
177 			dprintf("getrequests: daemon %s: port %d\n",
178 				Daemons[idx].d_name,
179 				ntohs(Daemons[idx].d_port));
180 	}
181 
182 	/* get a socket for the SMTP connection */
183 	for (idx = 0; idx < ndaemons; idx++)
184 		Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], TRUE);
185 
186 	if (opencontrolsocket() < 0)
187 		sm_syslog(LOG_WARNING, NOQID,
188 			  "daemon could not open control socket %s: %s",
189 			  ControlSocketName, errstring(errno));
190 
191 	(void) setsignal(SIGCHLD, reapchild);
192 
193 	/* write the pid to file */
194 	log_sendmail_pid(e);
195 
196 # if XDEBUG
197 	{
198 		char jbuf[MAXHOSTNAMELEN];
199 
200 		expand("\201j", jbuf, sizeof jbuf, e);
201 		j_has_dot = strchr(jbuf, '.') != NULL;
202 	}
203 # endif /* XDEBUG */
204 
205 	/* Add parent process as first item */
206 	proc_list_add(getpid(), "Sendmail daemon", PROC_DAEMON);
207 
208 	if (tTd(15, 1))
209 	{
210 		for (idx = 0; idx < ndaemons; idx++)
211 			dprintf("getrequests: daemon %s: %d\n",
212 				Daemons[idx].d_name,
213 				Daemons[idx].d_socket);
214 	}
215 
216 	for (;;)
217 	{
218 		register pid_t pid;
219 		auto SOCKADDR_LEN_T lotherend;
220 		bool timedout = FALSE;
221 		bool control = FALSE;
222 		int save_errno;
223 		int pipefd[2];
224 
225 		/* see if we are rejecting connections */
226 		(void) blocksignal(SIGALRM);
227 
228 		for (idx = 0; idx < ndaemons; idx++)
229 		{
230 			if (curtime() < Daemons[idx].d_refuse_connections_until)
231 				continue;
232 			if (refuseconnections(Daemons[idx].d_name, e, idx))
233 			{
234 				if (Daemons[idx].d_socket >= 0)
235 				{
236 				       /* close socket so peer fails quickly */
237 				       (void) close(Daemons[idx].d_socket);
238 				       Daemons[idx].d_socket = -1;
239 				}
240 
241 				/* refuse connections for next 15 seconds */
242 				Daemons[idx].d_refuse_connections_until = curtime() + 15;
243 			}
244 			else if (Daemons[idx].d_socket < 0 ||
245 				 Daemons[idx].d_firsttime)
246 			{
247 			      if (!Daemons[idx].d_firsttime && LogLevel >= 9)
248 				sm_syslog(LOG_INFO, NOQID,
249 					  "accepting connections again for daemon %s",
250 					  Daemons[idx].d_name);
251 
252 			      /* arrange to (re)open the socket if needed */
253 			      (void) opendaemonsocket(&Daemons[idx], FALSE);
254 			      Daemons[idx].d_firsttime = FALSE;
255 			}
256 		}
257 
258 		if (curtime() >= last_disk_space_check)
259 		{
260 			if (!enoughdiskspace(MinBlocksFree + 1, FALSE))
261 			{
262 				if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
263 				{
264 					/* log only if not logged before */
265 					if (LogLevel >= 9)
266 						sm_syslog(LOG_INFO, NOQID,
267 							  "rejecting new messages: min free: %d",
268 							  MinBlocksFree);
269 					sm_setproctitle(TRUE, e,
270 							"rejecting new messages: min free: %d",
271 							 MinBlocksFree);
272 					setbitn(D_ETRNONLY, Daemons[idx].d_flags);
273 				}
274 			}
275 			else if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
276 			{
277 				/* log only if not logged before */
278 				if (LogLevel >= 9)
279 					sm_syslog(LOG_INFO, NOQID,
280 						  "accepting new messages (again)");
281 				/* title will be set below */
282 				clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
283 			}
284 			/* only check disk space once a minute */
285 			last_disk_space_check = curtime() + 60;
286 		}
287 
288 # if XDEBUG
289 		/* check for disaster */
290 		{
291 			char jbuf[MAXHOSTNAMELEN];
292 
293 			expand("\201j", jbuf, sizeof jbuf, e);
294 			if (!wordinclass(jbuf, 'w'))
295 			{
296 				dumpstate("daemon lost $j");
297 				sm_syslog(LOG_ALERT, NOQID,
298 					  "daemon process doesn't have $j in $=w; see syslog");
299 				abort();
300 			}
301 			else if (j_has_dot && strchr(jbuf, '.') == NULL)
302 			{
303 				dumpstate("daemon $j lost dot");
304 				sm_syslog(LOG_ALERT, NOQID,
305 					  "daemon process $j lost dot; see syslog");
306 				abort();
307 			}
308 		}
309 # endif /* XDEBUG */
310 
311 # if 0
312 		/*
313 		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
314 		**  fix the SVr4 problem.  But it seems to have gone away,
315 		**  so is it worth doing this?
316 		*/
317 
318 		if (DaemonSocket >= 0 &&
319 		    SetNonBlocking(DaemonSocket, FALSE) < 0)
320 			log an error here;
321 # endif /* 0 */
322 		(void) releasesignal(SIGALRM);
323 
324 		for (;;)
325 		{
326 			int highest = -1;
327 			fd_set readfds;
328 			struct timeval timeout;
329 
330 			FD_ZERO(&readfds);
331 
332 			for (idx = 0; idx < ndaemons; idx++)
333 			{
334 				/* wait for a connection */
335 				if (Daemons[idx].d_socket >= 0)
336 				{
337 					if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
338 					{
339 						sm_setproctitle(TRUE, e,
340 								"accepting connections");
341 					}
342 					if (Daemons[idx].d_socket > highest)
343 						highest = Daemons[idx].d_socket;
344 					FD_SET((u_int)Daemons[idx].d_socket, &readfds);
345 				}
346 			}
347 
348 # if NETUNIX
349 			if (ControlSocket >= 0)
350 			{
351 				if (ControlSocket > highest)
352 					highest = ControlSocket;
353 				FD_SET(ControlSocket, &readfds);
354 			}
355 # endif /* NETUNIX */
356 
357 			/*
358 			**  if one socket is closed, set the timeout
359 			**  to 5 seconds (so it might get reopened soon),
360 			**  otherwise (all sockets open) 60.
361 			*/
362 			idx = 0;
363 			while (idx < ndaemons && Daemons[idx].d_socket >= 0)
364 				idx++;
365 			if (idx < ndaemons)
366 				timeout.tv_sec = 5;
367 			else
368 				timeout.tv_sec = 60;
369 			timeout.tv_usec = 0;
370 
371 			t = select(highest + 1, FDSET_CAST &readfds,
372 				   NULL, NULL, &timeout);
373 
374 			if (DoQueueRun)
375 				(void) runqueue(TRUE, FALSE);
376 			if (t <= 0)
377 			{
378 				timedout = TRUE;
379 				break;
380 			}
381 
382 			control = FALSE;
383 			errno = 0;
384 			curdaemon = -1;
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 				    FD_ISSET(Daemons[idx].d_socket, &readfds))
393 				{
394 					lotherend = Daemons[idx].d_socksize;
395 					t = accept(Daemons[idx].d_socket,
396 						   (struct sockaddr *)&RealHostAddr,
397 						   &lotherend);
398 					olddaemon = curdaemon = idx;
399 					break;
400 				}
401 				if (++idx >= ndaemons)
402 					idx = 0;
403 			}
404 # if NETUNIX
405 			if (curdaemon == -1 && ControlSocket >= 0 &&
406 				 FD_ISSET(ControlSocket, &readfds))
407 			{
408 				struct sockaddr_un sa_un;
409 
410 				lotherend = sizeof sa_un;
411 				t = accept(ControlSocket,
412 					   (struct sockaddr *)&sa_un,
413 					   &lotherend);
414 				control = TRUE;
415 			}
416 # endif /* NETUNIX */
417 			if (t >= 0 || errno != EINTR)
418 				break;
419 		}
420 		if (timedout)
421 		{
422 			timedout = FALSE;
423 			continue;
424 		}
425 		save_errno = errno;
426 		(void) blocksignal(SIGALRM);
427 		if (t < 0)
428 		{
429 			errno = save_errno;
430 			syserr("getrequests: accept");
431 
432 			/* arrange to re-open the socket next time around */
433 			(void) close(Daemons[curdaemon].d_socket);
434 			Daemons[curdaemon].d_socket = -1;
435 # if SO_REUSEADDR_IS_BROKEN
436 			/*
437 			**  Give time for bound socket to be released.
438 			**  This creates a denial-of-service if you can
439 			**  force accept() to fail on affected systems.
440 			*/
441 
442 			Daemons[curdaemon].d_refuse_connections_until = curtime() + 15;
443 # endif /* SO_REUSEADDR_IS_BROKEN */
444 			continue;
445 		}
446 
447 		if (!control)
448 		{
449 			/* set some daemon related macros */
450 			switch (Daemons[curdaemon].d_addr.sa.sa_family)
451 			{
452 			  case AF_UNSPEC:
453 				define(macid("{daemon_family}", NULL),
454 				       "unspec", &BlankEnvelope);
455 				break;
456 # if NETINET
457 			  case AF_INET:
458 				define(macid("{daemon_family}", NULL),
459 				       "inet", &BlankEnvelope);
460 				break;
461 # endif /* NETINET */
462 # if NETINET6
463 			  case AF_INET6:
464 				define(macid("{daemon_family}", NULL),
465 				       "inet6", &BlankEnvelope);
466 				break;
467 # endif /* NETINET6 */
468 # if NETISO
469 			  case AF_ISO:
470 				define(macid("{daemon_family}", NULL),
471 				       "iso", &BlankEnvelope);
472 				break;
473 # endif /* NETISO */
474 # if NETNS
475 			  case AF_NS:
476 				define(macid("{daemon_family}", NULL),
477 				       "ns", &BlankEnvelope);
478 				break;
479 # endif /* NETNS */
480 # if NETX25
481 			  case AF_CCITT:
482 				define(macid("{daemon_family}", NULL),
483 				       "x.25", &BlankEnvelope);
484 				break;
485 # endif /* NETX25 */
486 			}
487 			define(macid("{daemon_name}", NULL),
488 			       Daemons[curdaemon].d_name, &BlankEnvelope);
489 			if (Daemons[curdaemon].d_mflags != NULL)
490 				define(macid("{daemon_flags}", NULL),
491 				       Daemons[curdaemon].d_mflags,
492 				       &BlankEnvelope);
493 			else
494 				define(macid("{daemon_flags}", NULL),
495 				       "", &BlankEnvelope);
496 		}
497 
498 		/*
499 		**  Create a subprocess to process the mail.
500 		*/
501 
502 		if (tTd(15, 2))
503 			dprintf("getrequests: forking (fd = %d)\n", t);
504 
505 		/*
506 		**  advance state of PRNG
507 		**  this is necessary because otherwise all child processes
508 		**  will produce the same PRN sequence and hence the selection
509 		**  of a queue directory (and other things, e.g., MX selection)
510 		**  are not "really" random.
511 		*/
512 		(void) get_random();
513 
514 		/*
515 		**  Create a pipe to keep the child from writing to the
516 		**  socket until after the parent has closed it.  Otherwise
517 		**  the parent may hang if the child has closed it first.
518 		*/
519 
520 		if (pipe(pipefd) < 0)
521 			pipefd[0] = pipefd[1] = -1;
522 
523 		(void) blocksignal(SIGCHLD);
524 		pid = fork();
525 		if (pid < 0)
526 		{
527 			syserr("daemon: cannot fork");
528 			if (pipefd[0] != -1)
529 			{
530 				(void) close(pipefd[0]);
531 				(void) close(pipefd[1]);
532 			}
533 			(void) releasesignal(SIGCHLD);
534 			(void) sleep(10);
535 			(void) close(t);
536 			continue;
537 		}
538 
539 		if (pid == 0)
540 		{
541 			char *p;
542 			FILE *inchannel, *outchannel = NULL;
543 
544 			/*
545 			**  CHILD -- return to caller.
546 			**	Collect verified idea of sending host.
547 			**	Verify calling user id if possible here.
548 			*/
549 
550 			if (!control)
551 			{
552 				define(macid("{daemon_addr}", NULL),
553 				       newstr(anynet_ntoa(&Daemons[curdaemon].d_addr)),
554 				       &BlankEnvelope);
555 				(void) snprintf(status, sizeof status, "%d",
556 						ntohs(Daemons[curdaemon].d_port));
557 				define(macid("{daemon_port}", NULL),
558 				       newstr(status), &BlankEnvelope);
559 			}
560 
561 			(void) releasesignal(SIGALRM);
562 			(void) releasesignal(SIGCHLD);
563 			(void) setsignal(SIGCHLD, SIG_DFL);
564 			(void) setsignal(SIGHUP, intsig);
565 			for (idx = 0; idx < ndaemons; idx++)
566 			{
567 				if (Daemons[idx].d_socket >= 0)
568 					(void) close(Daemons[idx].d_socket);
569 			}
570 			clrcontrol();
571 
572 			/* Avoid SMTP daemon actions if control command */
573 			if (control)
574 			{
575 				/* Add control socket process */
576 				proc_list_add(getpid(), "console socket child",
577 					PROC_CONTROL_CHILD);
578 			}
579 			else
580 			{
581 				proc_list_clear();
582 
583 				/* Add parent process as first child item */
584 				proc_list_add(getpid(), "daemon child",
585 					      PROC_DAEMON_CHILD);
586 
587 				/* don't schedule queue runs if ETRN */
588 				QueueIntvl = 0;
589 
590 				sm_setproctitle(TRUE, e, "startup with %s",
591 						anynet_ntoa(&RealHostAddr));
592 			}
593 
594 			if (pipefd[0] != -1)
595 			{
596 				auto char c;
597 
598 				/*
599 				**  Wait for the parent to close the write end
600 				**  of the pipe, which we will see as an EOF.
601 				**  This guarantees that we won't write to the
602 				**  socket until after the parent has closed
603 				**  the pipe.
604 				*/
605 
606 				/* close the write end of the pipe */
607 				(void) close(pipefd[1]);
608 
609 				/* we shouldn't be interrupted, but ... */
610 				while (read(pipefd[0], &c, 1) < 0 &&
611 				       errno == EINTR)
612 					continue;
613 				(void) close(pipefd[0]);
614 			}
615 
616 			/* control socket processing */
617 			if (control)
618 			{
619 				control_command(t, e);
620 
621 				/* NOTREACHED */
622 				exit(EX_SOFTWARE);
623 			}
624 
625 			/* determine host name */
626 			p = hostnamebyanyaddr(&RealHostAddr);
627 			if (strlen(p) > (SIZE_T) MAXNAME)
628 				p[MAXNAME] = '\0';
629 			RealHostName = newstr(p);
630 			if (RealHostName[0] == '[')
631 			{
632 				/* TEMP, FAIL: which one? */
633 				define(macid("{client_resolve}", NULL),
634 				       (h_errno == TRY_AGAIN) ? "TEMP" : "FAIL",
635 				       &BlankEnvelope);
636 			}
637 			else
638 				define(macid("{client_resolve}", NULL), "OK",
639 				       &BlankEnvelope);
640 			sm_setproctitle(TRUE, e, "startup with %s", p);
641 
642 			if ((inchannel = fdopen(t, "r")) == NULL ||
643 			    (t = dup(t)) < 0 ||
644 			    (outchannel = fdopen(t, "w")) == NULL)
645 			{
646 				syserr("cannot open SMTP server channel, fd=%d", t);
647 				finis(FALSE, EX_OK);
648 			}
649 
650 			InChannel = inchannel;
651 			OutChannel = outchannel;
652 			DisConnected = FALSE;
653 
654 # ifdef XLA
655 			if (!xla_host_ok(RealHostName))
656 			{
657 				message("421 4.4.5 Too many SMTP sessions for this host");
658 				finis(FALSE, EX_OK);
659 			}
660 # endif /* XLA */
661 			/* find out name for interface of connection */
662 			if (getsockname(fileno(InChannel), &sa.sa,
663 					&len) == 0)
664 			{
665 				p = hostnamebyanyaddr(&sa);
666 				if (tTd(15, 9))
667 					dprintf("getreq: got name %s\n", p);
668 				define(macid("{if_name}", NULL),
669 				       newstr(p), &BlankEnvelope);
670 
671 				/* do this only if it is not the loopback */
672 				/* interface: how to figure out? XXX */
673 				if (!isloopback(sa))
674 				{
675 					define(macid("{if_addr}", NULL),
676 					       newstr(anynet_ntoa(&sa)),
677 					       &BlankEnvelope);
678 					p = xalloc(5);
679 					snprintf(p, 4, "%d", sa.sa.sa_family);
680 					define(macid("{if_family}", NULL), p,
681 					       &BlankEnvelope);
682 					if (tTd(15, 7))
683 						dprintf("getreq: got addr %s and family %s\n",
684 							macvalue(macid("{if_addr}", NULL),
685 								 &BlankEnvelope),
686 							macvalue(macid("{if_addr}", NULL),
687 								 &BlankEnvelope));
688 				}
689 				else
690 				{
691 					define(macid("{if_addr}", NULL), NULL,
692 					       &BlankEnvelope);
693 					define(macid("{if_family}", NULL), NULL,
694 					       &BlankEnvelope);
695 				}
696 			}
697 			else
698 			{
699 				if (tTd(15, 7))
700 					dprintf("getreq: getsockname failed\n");
701 				define(macid("{if_name}", NULL), NULL,
702 				       &BlankEnvelope);
703 				define(macid("{if_addr}", NULL), NULL,
704 				       &BlankEnvelope);
705 				define(macid("{if_family}", NULL), NULL,
706 				       &BlankEnvelope);
707 			}
708 			break;
709 		}
710 
711 		/* parent -- keep track of children */
712 		if (control)
713 		{
714 			snprintf(status, sizeof status, "control socket server child");
715 			proc_list_add(pid, status, PROC_CONTROL);
716 		}
717 		else
718 		{
719 			snprintf(status, sizeof status,
720 				 "SMTP server child for %s",
721 				 anynet_ntoa(&RealHostAddr));
722 			proc_list_add(pid, status, PROC_DAEMON);
723 		}
724 		(void) releasesignal(SIGCHLD);
725 
726 		/* close the read end of the synchronization pipe */
727 		if (pipefd[0] != -1)
728 		{
729 			(void) close(pipefd[0]);
730 			pipefd[0] = -1;
731 		}
732 
733 		/* close the port so that others will hang (for a while) */
734 		(void) close(t);
735 
736 		/* release the child by closing the read end of the sync pipe */
737 		if (pipefd[1] != -1)
738 		{
739 			(void) close(pipefd[1]);
740 			pipefd[1] = -1;
741 		}
742 	}
743 
744 	if (tTd(15, 2))
745 		dprintf("getreq: returning\n");
746 	return &Daemons[curdaemon].d_flags;
747 }
748 /*
749 **  OPENDAEMONSOCKET -- open SMTP socket
750 **
751 **	Deals with setting all appropriate options.
752 **
753 **	Parameters:
754 **		d -- the structure for the daemon to open.
755 **		firsttime -- set if this is the initial open.
756 **
757 **	Returns:
758 **		Size in bytes of the daemon socket addr.
759 **
760 **	Side Effects:
761 **		Leaves DaemonSocket set to the open socket.
762 **		Exits if the socket cannot be created.
763 */
764 
765 # define MAXOPENTRIES	10	/* maximum number of tries to open connection */
766 
767 static int
768 opendaemonsocket(d, firsttime)
769 	struct daemon *d;
770 	bool firsttime;
771 {
772 	int on = 1;
773 	int fdflags;
774 	SOCKADDR_LEN_T socksize = 0;
775 	int ntries = 0;
776 	int save_errno;
777 
778 	if (tTd(15, 2))
779 		dprintf("opendaemonsocket(%s)\n", d->d_name);
780 
781 	do
782 	{
783 		if (ntries > 0)
784 			(void) sleep(5);
785 		if (firsttime || d->d_socket < 0)
786 		{
787 			d->d_socket = socket(d->d_addr.sa.sa_family,
788 					     SOCK_STREAM, 0);
789 			if (d->d_socket < 0)
790 			{
791 				save_errno = errno;
792 				syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", d->d_name);
793 			  severe:
794 				if (LogLevel > 0)
795 					sm_syslog(LOG_ALERT, NOQID,
796 						  "daemon %s: problem creating SMTP socket", d->d_name);
797 				d->d_socket = -1;
798 				continue;
799 			}
800 
801 			/* turn on network debugging? */
802 			if (tTd(15, 101))
803 				(void) setsockopt(d->d_socket, SOL_SOCKET,
804 						  SO_DEBUG, (char *)&on,
805 						  sizeof on);
806 
807 			(void) setsockopt(d->d_socket, SOL_SOCKET,
808 					  SO_REUSEADDR, (char *)&on, sizeof on);
809 			(void) setsockopt(d->d_socket, SOL_SOCKET,
810 					  SO_KEEPALIVE, (char *)&on, sizeof on);
811 
812 # ifdef SO_RCVBUF
813 			if (d->d_tcprcvbufsize > 0)
814 			{
815 				if (setsockopt(d->d_socket, SOL_SOCKET,
816 					       SO_RCVBUF,
817 					       (char *) &d->d_tcprcvbufsize,
818 					       sizeof(d->d_tcprcvbufsize)) < 0)
819 					syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
820 			}
821 # endif /* SO_RCVBUF */
822 # ifdef SO_SNDBUF
823 			if (d->d_tcpsndbufsize > 0)
824 			{
825 				if (setsockopt(d->d_socket, SOL_SOCKET,
826 					       SO_SNDBUF,
827 					       (char *) &d->d_tcpsndbufsize,
828 					       sizeof(d->d_tcpsndbufsize)) < 0)
829 					syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
830 			}
831 # endif /* SO_SNDBUF */
832 
833 			if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
834 			    fcntl(d->d_socket, F_SETFD,
835 				  fdflags | FD_CLOEXEC) == -1)
836 			{
837 				save_errno = errno;
838 				syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
839 				       d->d_name,
840 				       fdflags == -1 ? "get" : "set",
841 				       errstring(save_errno));
842 				(void) close(d->d_socket);
843 				goto severe;
844 			}
845 
846 			switch (d->d_addr.sa.sa_family)
847 			{
848 # if NETINET
849 			  case AF_INET:
850 				socksize = sizeof d->d_addr.sin;
851 				break;
852 # endif /* NETINET */
853 
854 # if NETINET6
855 			  case AF_INET6:
856 				socksize = sizeof d->d_addr.sin6;
857 				break;
858 # endif /* NETINET6 */
859 
860 # if NETISO
861 			  case AF_ISO:
862 				socksize = sizeof d->d_addr.siso;
863 				break;
864 # endif /* NETISO */
865 
866 			  default:
867 				socksize = sizeof d->d_addr;
868 				break;
869 			}
870 
871 			if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
872 			{
873 				/* probably another daemon already */
874 				save_errno = errno;
875 				syserr("opendaemonsocket: daemon %s: cannot bind",
876 				       d->d_name);
877 				(void) close(d->d_socket);
878 				goto severe;
879 			}
880 		}
881 		if (!firsttime &&
882 		    listen(d->d_socket, d->d_listenqueue) < 0)
883 		{
884 			save_errno = errno;
885 			syserr("opendaemonsocket: daemon %s: cannot listen",
886 			       d->d_name);
887 			(void) close(d->d_socket);
888 			goto severe;
889 		}
890 		return socksize;
891 	} while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
892 	syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
893 	       d->d_name);
894 	/* NOTREACHED */
895 	return -1;  /* avoid compiler warning on IRIX */
896 }
897 /*
898 **  SETUPDAEMON -- setup socket for daemon
899 **
900 **	Parameters:
901 **		daemonaddr -- socket for daemon
902 **		daemon -- number of daemon
903 **
904 **	Returns:
905 **		port number on which daemon should run
906 **
907 */
908 static u_short
909 setupdaemon(daemonaddr)
910 	SOCKADDR *daemonaddr;
911 {
912 	u_short port;
913 
914 	/*
915 	**  Set up the address for the mailer.
916 	*/
917 
918 	if (daemonaddr->sa.sa_family == AF_UNSPEC)
919 	{
920 		memset(daemonaddr, '\0', sizeof *daemonaddr);
921 # if NETINET
922 		daemonaddr->sa.sa_family = AF_INET;
923 # endif /* NETINET */
924 	}
925 
926 	switch (daemonaddr->sa.sa_family)
927 	{
928 # if NETINET
929 	  case AF_INET:
930 		if (daemonaddr->sin.sin_addr.s_addr == 0)
931 			daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
932 		port = daemonaddr->sin.sin_port;
933 		break;
934 # endif /* NETINET */
935 
936 # if NETINET6
937 	  case AF_INET6:
938 		if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
939 			daemonaddr->sin6.sin6_addr = in6addr_any;
940 		port = daemonaddr->sin6.sin6_port;
941 		break;
942 # endif /* NETINET6 */
943 
944 	  default:
945 		/* unknown protocol */
946 		port = 0;
947 		break;
948 	}
949 	if (port == 0)
950 	{
951 # ifdef NO_GETSERVBYNAME
952 		port = htons(25);
953 # else /* NO_GETSERVBYNAME */
954 		{
955 			register struct servent *sp;
956 
957 			sp = getservbyname("smtp", "tcp");
958 			if (sp == NULL)
959 			{
960 				syserr("554 5.3.5 service \"smtp\" unknown");
961 				port = htons(25);
962 			}
963 			else
964 				port = sp->s_port;
965 		}
966 # endif /* NO_GETSERVBYNAME */
967 	}
968 
969 	switch (daemonaddr->sa.sa_family)
970 	{
971 # if NETINET
972 	  case AF_INET:
973 		daemonaddr->sin.sin_port = port;
974 		break;
975 # endif /* NETINET */
976 
977 # if NETINET6
978 	  case AF_INET6:
979 		daemonaddr->sin6.sin6_port = port;
980 		break;
981 # endif /* NETINET6 */
982 
983 	  default:
984 		/* unknown protocol */
985 		break;
986 	}
987 	return(port);
988 }
989 /*
990 **  CLRDAEMON -- reset the daemon connection
991 **
992 **	Parameters:
993 **		none.
994 **
995 **	Returns:
996 **		none.
997 **
998 **	Side Effects:
999 **		releases any resources used by the passive daemon.
1000 */
1001 
1002 void
1003 clrdaemon()
1004 {
1005 	int i;
1006 
1007 	for (i = 0; i < ndaemons; i++)
1008 	{
1009 		if (Daemons[i].d_socket >= 0)
1010 			(void) close(Daemons[i].d_socket);
1011 		Daemons[i].d_socket = -1;
1012 	}
1013 }
1014 /*
1015 **  SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
1016 **
1017 **	Parameters:
1018 **		p -- the options line.
1019 **		d -- the daemon structure to fill in.
1020 **
1021 **	Returns:
1022 **		none.
1023 */
1024 
1025 static void
1026 setsockaddroptions(p, d)
1027 	register char *p;
1028 	struct daemon *d;
1029 {
1030 # if NETISO
1031 	short port;
1032 # endif /* NETISO */
1033 	int l;
1034 	char *h, *flags;
1035 
1036 # if NETINET
1037 	if (d->d_addr.sa.sa_family == AF_UNSPEC)
1038 		d->d_addr.sa.sa_family = AF_INET;
1039 # endif /* NETINET */
1040 
1041 	while (p != NULL)
1042 	{
1043 		register char *f;
1044 		register char *v;
1045 
1046 		while (isascii(*p) && isspace(*p))
1047 			p++;
1048 		if (*p == '\0')
1049 			break;
1050 		f = p;
1051 		p = strchr(p, ',');
1052 		if (p != NULL)
1053 			*p++ = '\0';
1054 		v = strchr(f, '=');
1055 		if (v == NULL)
1056 			continue;
1057 		while (isascii(*++v) && isspace(*v))
1058 			continue;
1059 		if (isascii(*f) && islower(*f))
1060 			*f = toupper(*f);
1061 
1062 		switch (*f)
1063 		{
1064 		  case 'F':		/* address family */
1065 			if (isascii(*v) && isdigit(*v))
1066 				d->d_addr.sa.sa_family = atoi(v);
1067 # if NETINET
1068 			else if (strcasecmp(v, "inet") == 0)
1069 				d->d_addr.sa.sa_family = AF_INET;
1070 # endif /* NETINET */
1071 # if NETINET6
1072 			else if (strcasecmp(v, "inet6") == 0)
1073 				d->d_addr.sa.sa_family = AF_INET6;
1074 # endif /* NETINET6 */
1075 # if NETISO
1076 			else if (strcasecmp(v, "iso") == 0)
1077 				d->d_addr.sa.sa_family = AF_ISO;
1078 # endif /* NETISO */
1079 # if NETNS
1080 			else if (strcasecmp(v, "ns") == 0)
1081 				d->d_addr.sa.sa_family = AF_NS;
1082 # endif /* NETNS */
1083 # if NETX25
1084 			else if (strcasecmp(v, "x.25") == 0)
1085 				d->d_addr.sa.sa_family = AF_CCITT;
1086 # endif /* NETX25 */
1087 			else
1088 				syserr("554 5.3.5 Unknown address family %s in Family=option",
1089 				       v);
1090 			break;
1091 
1092 		  case 'A':		/* address */
1093 			switch (d->d_addr.sa.sa_family)
1094 			{
1095 # if NETINET
1096 			  case AF_INET:
1097 				if (!isascii(*v) || !isdigit(*v) ||
1098 				    ((d->d_addr.sin.sin_addr.s_addr = inet_addr(v)) == INADDR_NONE))
1099 				{
1100 					register struct hostent *hp;
1101 
1102 					hp = sm_gethostbyname(v, AF_INET);
1103 					if (hp == NULL)
1104 						syserr("554 5.3.0 host \"%s\" unknown",
1105 						       v);
1106 					else
1107 					{
1108 						while (*(hp->h_addr_list) &&
1109 						       hp->h_addrtype != AF_INET)
1110 							hp->h_addr_list++;
1111 						if (*(hp->h_addr_list) == NULL)
1112 							syserr("554 5.3.0 host \"%s\" unknown",
1113 							       v);
1114 						else
1115 							memmove(&d->d_addr.sin.sin_addr,
1116 								*(hp->h_addr_list),
1117 								INADDRSZ);
1118 					}
1119 				}
1120 				break;
1121 # endif /* NETINET */
1122 
1123 # if NETINET6
1124 			  case AF_INET6:
1125 				if (!isascii(*v) || !isxdigit(*v) ||
1126 				    inet_pton(AF_INET6, v,
1127 					      &d->d_addr.sin6.sin6_addr) != 1)
1128 				{
1129 					register struct hostent *hp;
1130 
1131 					hp = sm_gethostbyname(v, AF_INET6);
1132 					if (hp == NULL)
1133 						syserr("554 5.3.0 host \"%s\" unknown",
1134 						       v);
1135 					else
1136 					{
1137 						while (*(hp->h_addr_list) &&
1138 						       hp->h_addrtype != AF_INET6)
1139 							hp->h_addr_list++;
1140 						if (*(hp->h_addr_list) == NULL)
1141 							syserr("554 5.3.0 host \"%s\" unknown",
1142 							       v);
1143 						else
1144 							memmove(&d->d_addr.sin6.sin6_addr,
1145 								*(hp->h_addr_list),
1146 								IN6ADDRSZ);
1147 					}
1148 				}
1149 				break;
1150 # endif /* NETINET6 */
1151 
1152 			  default:
1153 				syserr("554 5.3.5 address= option unsupported for family %d",
1154 				       d->d_addr.sa.sa_family);
1155 				break;
1156 			}
1157 			break;
1158 
1159 		  case 'P':		/* port */
1160 			switch (d->d_addr.sa.sa_family)
1161 			{
1162 # if NETINET
1163 			  case AF_INET:
1164 				if (isascii(*v) && isdigit(*v))
1165 					d->d_addr.sin.sin_port = htons((u_short)atoi((const char *)v));
1166 				else
1167 				{
1168 #  ifdef NO_GETSERVBYNAME
1169 					syserr("554 5.3.5 invalid port number: %s",
1170 					       v);
1171 #  else /* NO_GETSERVBYNAME */
1172 					register struct servent *sp;
1173 
1174 					sp = getservbyname(v, "tcp");
1175 					if (sp == NULL)
1176 						syserr("554 5.3.5 service \"%s\" unknown",
1177 						       v);
1178 					else
1179 						d->d_addr.sin.sin_port = sp->s_port;
1180 #  endif /* NO_GETSERVBYNAME */
1181 				}
1182 				break;
1183 # endif /* NETINET */
1184 
1185 # if NETINET6
1186 			  case AF_INET6:
1187 				if (isascii(*v) && isdigit(*v))
1188 					d->d_addr.sin6.sin6_port = htons((u_short)atoi(v));
1189 				else
1190 				{
1191 #  ifdef NO_GETSERVBYNAME
1192 					syserr("554 5.3.5 invalid port number: %s",
1193 					       v);
1194 #  else /* NO_GETSERVBYNAME */
1195 					register struct servent *sp;
1196 
1197 					sp = getservbyname(v, "tcp");
1198 					if (sp == NULL)
1199 						syserr("554 5.3.5 service \"%s\" unknown",
1200 						       v);
1201 					else
1202 						d->d_addr.sin6.sin6_port = sp->s_port;
1203 #  endif /* NO_GETSERVBYNAME */
1204 				}
1205 				break;
1206 # endif /* NETINET6 */
1207 
1208 # if NETISO
1209 			  case AF_ISO:
1210 				/* assume two byte transport selector */
1211 				if (isascii(*v) && isdigit(*v))
1212 					port = htons((u_short)atoi(v));
1213 				else
1214 				{
1215 #  ifdef NO_GETSERVBYNAME
1216 					syserr("554 5.3.5 invalid port number: %s",
1217 					       v);
1218 #  else /* NO_GETSERVBYNAME */
1219 					register struct servent *sp;
1220 
1221 					sp = getservbyname(v, "tcp");
1222 					if (sp == NULL)
1223 						syserr("554 5.3.5 service \"%s\" unknown",
1224 						       v);
1225 					else
1226 						port = sp->s_port;
1227 #  endif /* NO_GETSERVBYNAME */
1228 				}
1229 				memmove(TSEL(&d->d_addr.siso),
1230 					(char *) &port, 2);
1231 				break;
1232 # endif /* NETISO */
1233 
1234 			  default:
1235 				syserr("554 5.3.5 Port= option unsupported for family %d",
1236 				       d->d_addr.sa.sa_family);
1237 				break;
1238 			}
1239 			break;
1240 
1241 		  case 'L':		/* listen queue size */
1242 			d->d_listenqueue = atoi(v);
1243 			break;
1244 
1245 		  case 'M':		/* modifiers (flags) */
1246 			l = 3 * strlen(v) + 3;
1247 			h = v;
1248 			flags = xalloc(l);
1249 			d->d_mflags = flags;
1250 			for (; *h != '\0'; h++)
1251 			{
1252 				if (!(isascii(*h) && isspace(*h)))
1253 				{
1254 					if (flags != d->d_mflags)
1255 						*f++ = ' ';
1256 					*flags++ = *h;
1257 					if (isupper(*h))
1258 						*flags++ = *h;
1259 				}
1260 			}
1261 			*flags++ = '\0';
1262 			for (; *v != '\0'; v++)
1263 				if (!(isascii(*v) && isspace(*v)))
1264 					setbitn(*v, d->d_flags);
1265 			break;
1266 
1267 		  case 'S':		/* send buffer size */
1268 			d->d_tcpsndbufsize = atoi(v);
1269 			break;
1270 
1271 		  case 'R':		/* receive buffer size */
1272 			d->d_tcprcvbufsize = atoi(v);
1273 			break;
1274 
1275 		  case 'N':		/* name */
1276 			d->d_name = v;
1277 			break;
1278 
1279 		  default:
1280 			syserr("554 5.3.5 PortOptions parameter \"%s\" unknown",
1281 			       f);
1282 		}
1283 	}
1284 }
1285 /*
1286 **  SETDAEMONOPTIONS -- set options for running the MTA daemon
1287 **
1288 **	Parameters:
1289 **		p -- the options line.
1290 **
1291 **	Returns:
1292 **		TRUE if successful, FALSE otherwise.
1293 */
1294 
1295 bool
1296 setdaemonoptions(p)
1297 	register char *p;
1298 {
1299 	if (ndaemons >= MAXDAEMONS)
1300 		return FALSE;
1301 	Daemons[ndaemons].d_socket = -1;
1302 	Daemons[ndaemons].d_listenqueue = 10;
1303 	clrbitmap(Daemons[ndaemons].d_flags);
1304 	setsockaddroptions(p, &Daemons[ndaemons]);
1305 
1306 	if (Daemons[ndaemons].d_name != NULL)
1307 		Daemons[ndaemons].d_name = newstr(Daemons[ndaemons].d_name);
1308 	else
1309 	{
1310 		char num[30];
1311 
1312 		snprintf(num, sizeof num, "Daemon%d", ndaemons);
1313 		Daemons[ndaemons].d_name = newstr(num);
1314 	}
1315 
1316 	if (tTd(37, 1))
1317 	{
1318 		dprintf("Daemon %s flags: ", Daemons[ndaemons].d_name);
1319 		if (bitnset(D_ETRNONLY, Daemons[ndaemons].d_flags))
1320 			dprintf("ETRNONLY ");
1321 		if (bitnset(D_NOETRN, Daemons[ndaemons].d_flags))
1322 			dprintf("NOETRN ");
1323 		dprintf("\n");
1324 	}
1325 	++ndaemons;
1326 	return TRUE;
1327 }
1328 /*
1329 **  INITDAEMON -- initialize daemon if not yet done.
1330 **
1331 **	Parameters:
1332 **		none
1333 **
1334 **	Returns:
1335 **		none
1336 **
1337 **	Side Effects:
1338 **		initializes structure for one daemon.
1339 */
1340 void
1341 initdaemon()
1342 {
1343 	if (ndaemons == 0)
1344 	{
1345 		Daemons[ndaemons].d_socket = -1;
1346 		Daemons[ndaemons].d_listenqueue = 10;
1347 		Daemons[ndaemons].d_name = "Daemon0";
1348 		ndaemons = 1;
1349 	}
1350 }
1351 /*
1352 **  SETCLIENTOPTIONS -- set options for running the client
1353 **
1354 **	Parameters:
1355 **		p -- the options line.
1356 **
1357 **	Returns:
1358 **		none.
1359 */
1360 
1361 static SOCKADDR	ClientAddr;		/* address for client */
1362 
1363 void
1364 setclientoptions(p)
1365 	register char *p;
1366 {
1367 	struct daemon d;
1368 	extern ENVELOPE BlankEnvelope;
1369 
1370 	memset(&d, '\0', sizeof d);
1371 	setsockaddroptions(p, &d);
1372 
1373 	/* grab what we need */
1374 	memcpy(&ClientAddr, &d.d_addr, sizeof ClientAddr);
1375 	TcpSndBufferSize = d.d_tcpsndbufsize;
1376 	TcpRcvBufferSize = d.d_tcprcvbufsize;
1377 	if (d.d_mflags != NULL)
1378 		define(macid("{client_flags}", NULL), d.d_mflags,
1379 		       &BlankEnvelope);
1380 	else
1381 		define(macid("{client_flags}", NULL), "", &BlankEnvelope);
1382 }
1383 /*
1384 **  ADDR_FAMILY -- determine address family from address
1385 **
1386 **	Parameters:
1387 **		addr -- the string representation of the address
1388 **
1389 **	Returns:
1390 **		AF_INET, AF_INET6 or AF_UNSPEC
1391 **
1392 **	Side Effects:
1393 **		none.
1394 */
1395 
1396 static int
1397 addr_family(addr)
1398 	char *addr;
1399 {
1400 # if NETINET6
1401 	SOCKADDR clt_addr;
1402 # endif /* NETINET6 */
1403 
1404 # if NETINET
1405 	if (inet_addr(addr) != INADDR_NONE)
1406 	{
1407 		if (tTd(16, 9))
1408 			printf("addr_family(%s): INET\n", addr);
1409 		return AF_INET;
1410 	}
1411 # endif /* NETINET */
1412 # if NETINET6
1413 	if (inet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
1414 	{
1415 		if (tTd(16, 9))
1416 			printf("addr_family(%s): INET6\n", addr);
1417 		return AF_INET6;
1418 	}
1419 # endif /* NETINET6 */
1420 	if (tTd(16, 9))
1421 		printf("addr_family(%s): UNSPEC\n", addr);
1422 	return AF_UNSPEC;
1423 }
1424 /*
1425 **  MAKECONNECTION -- make a connection to an SMTP socket on a machine.
1426 **
1427 **	Parameters:
1428 **		host -- the name of the host.
1429 **		port -- the port number to connect to.
1430 **		mci -- a pointer to the mail connection information
1431 **			structure to be filled in.
1432 **		e -- the current envelope.
1433 **
1434 **	Returns:
1435 **		An exit code telling whether the connection could be
1436 **			made and if not why not.
1437 **
1438 **	Side Effects:
1439 **		none.
1440 */
1441 
1442 static jmp_buf	CtxConnectTimeout;
1443 
1444 SOCKADDR	CurHostAddr;		/* address of current host */
1445 
1446 int
1447 makeconnection(host, port, mci, e)
1448 	char *host;
1449 	volatile u_int port;
1450 	register MCI *mci;
1451 	ENVELOPE *e;
1452 {
1453 	register volatile int addrno = 0;
1454 	register volatile int s;
1455 	register struct hostent *volatile hp = (struct hostent *)NULL;
1456 	SOCKADDR addr;
1457 	SOCKADDR clt_addr;
1458 	int save_errno = 0;
1459 	volatile SOCKADDR_LEN_T addrlen;
1460 	volatile bool firstconnect;
1461 	EVENT *volatile ev = NULL;
1462 # if NETINET6
1463 	volatile bool v6found = FALSE;
1464 # endif /* NETINET6 */
1465 	volatile int family = InetMode;
1466 	SOCKADDR_LEN_T len;
1467 	volatile SOCKADDR_LEN_T socksize = 0;
1468 	volatile bool clt_bind;
1469 	BITMAP256 d_flags;
1470 	char *p;
1471 	extern ENVELOPE BlankEnvelope;
1472 
1473 	/* retranslate ${daemon_flags} into bitmap */
1474 	clrbitmap(d_flags);
1475 	if ((p = macvalue(macid("{daemon_flags}", NULL), e)) != NULL)
1476 	{
1477 		for (; *p != '\0'; p++)
1478 		{
1479 			if (!(isascii(*p) && isspace(*p)))
1480 				setbitn(*p, d_flags);
1481 		}
1482 	}
1483 
1484 	/* "add" ${client_flags} to bitmap */
1485 	if ((p = macvalue(macid("{client_flags}", NULL), e)) != NULL)
1486 	{
1487 		for (; *p != '\0'; p++)
1488 		{
1489 			/* look for just this one flag */
1490 			if (*p == D_IFNHELO)
1491 			{
1492 				setbitn(*p, d_flags);
1493 				break;
1494 			}
1495 		}
1496 	}
1497 
1498 # if NETINET6
1499  v4retry:
1500 # endif /* NETINET6 */
1501 	clt_bind = FALSE;
1502 
1503 	/* Set up the address for outgoing connection. */
1504 	if (bitnset(D_BINDIF, d_flags) &&
1505 	    (p = macvalue(macid("{if_addr}", NULL), e)) != NULL)
1506 	{
1507 # if NETINET6
1508 		char p6[INET6_ADDRSTRLEN];
1509 # endif /* NETINET6 */
1510 
1511 		memset(&clt_addr, '\0', sizeof clt_addr);
1512 
1513 		/* infer the address family from the address itself */
1514 		clt_addr.sa.sa_family = addr_family(p);
1515 		switch (clt_addr.sa.sa_family)
1516 		{
1517 # if NETINET
1518 		  case AF_INET:
1519 			if ((clt_addr.sin.sin_addr.s_addr = inet_addr(p))
1520 			    != INADDR_NONE)
1521 			{
1522 				clt_bind = TRUE;
1523 				socksize = sizeof (struct sockaddr_in);
1524 			}
1525 			else if (clt_addr.sin.sin_port != 0)
1526 			{
1527 				clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
1528 				clt_bind = TRUE;
1529 				socksize = sizeof (struct sockaddr_in);
1530 			}
1531 			break;
1532 # endif /* NETINET */
1533 
1534 # if NETINET6
1535 		  case AF_INET6:
1536 			if (inet_addr(p) != INADDR_NONE)
1537 				snprintf(p6, sizeof p6, "::ffff:%s", p);
1538 			else
1539 				strlcpy(p6, p, sizeof p6);
1540 			if (inet_pton(AF_INET6, p6,
1541 				      &clt_addr.sin6.sin6_addr) == 1)
1542 			{
1543 				clt_bind = TRUE;
1544 				socksize = sizeof (struct sockaddr_in6);
1545 			}
1546 			else if (clt_addr.sin6.sin6_port != 0)
1547 			{
1548 				if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
1549 					clt_addr.sin6.sin6_addr = in6addr_any;
1550 				clt_bind = TRUE;
1551 				socksize = sizeof (struct sockaddr_in6);
1552 			}
1553 			break;
1554 # endif /* NETINET6 */
1555 
1556 # if 0
1557 		  default:
1558 			syserr("554 5.3.5 Address= option unsupported for family %d",
1559 			       clt_addr.sa.sa_family);
1560 			break;
1561 # endif /* 0 */
1562 		}
1563 		if (clt_bind)
1564 			family = clt_addr.sa.sa_family;
1565 	}
1566 	else
1567 	{
1568 		STRUCTCOPY(ClientAddr, clt_addr);
1569 		if (clt_addr.sa.sa_family == AF_UNSPEC)
1570 			clt_addr.sa.sa_family = InetMode;
1571 		switch (clt_addr.sa.sa_family)
1572 		{
1573 # if NETINET
1574 		  case AF_INET:
1575 			if (clt_addr.sin.sin_addr.s_addr == 0)
1576 				clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
1577 			else
1578 				clt_bind = TRUE;
1579 			if (clt_addr.sin.sin_port != 0)
1580 				clt_bind = TRUE;
1581 			socksize = sizeof (struct sockaddr_in);
1582 			break;
1583 # endif /* NETINET */
1584 # if NETINET6
1585 		  case AF_INET6:
1586 			if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
1587 				clt_addr.sin6.sin6_addr = in6addr_any;
1588 			else
1589 				clt_bind = TRUE;
1590 			socksize = sizeof (struct sockaddr_in6);
1591 			if (clt_addr.sin6.sin6_port != 0)
1592 				clt_bind = TRUE;
1593 			break;
1594 # endif /* NETINET6 */
1595 # if NETISO
1596 		  case AF_ISO:
1597 			socksize = sizeof clt_addr.siso;
1598 			clt_bind = TRUE;
1599 			break;
1600 # endif /* NETISO */
1601 		  default:
1602 			break;
1603 		}
1604 	}
1605 
1606 	/*
1607 	**  Set up the address for the mailer.
1608 	**	Accept "[a.b.c.d]" syntax for host name.
1609 	*/
1610 
1611 # if NAMED_BIND
1612 	h_errno = 0;
1613 # endif /* NAMED_BIND */
1614 	errno = 0;
1615 	memset(&CurHostAddr, '\0', sizeof CurHostAddr);
1616 	memset(&addr, '\0', sizeof addr);
1617 	SmtpPhase = mci->mci_phase = "initial connection";
1618 	CurHostName = host;
1619 
1620 	if (host[0] == '[')
1621 	{
1622 		p = strchr(host, ']');
1623 		if (p != NULL)
1624 		{
1625 # if NETINET
1626 			unsigned long hid = INADDR_NONE;
1627 # endif /* NETINET */
1628 # if NETINET6
1629 			struct sockaddr_in6 hid6;
1630 # endif /* NETINET6 */
1631 
1632 			*p = '\0';
1633 # if NETINET6
1634 			memset(&hid6, '\0', sizeof hid6);
1635 # endif /* NETINET6 */
1636 # if NETINET
1637 			if (family == AF_INET &&
1638 			    (hid = inet_addr(&host[1])) != INADDR_NONE)
1639 			{
1640 				addr.sin.sin_family = AF_INET;
1641 				addr.sin.sin_addr.s_addr = hid;
1642 			}
1643 			else
1644 # endif /* NETINET */
1645 # if NETINET6
1646 			if (family == AF_INET6 &&
1647 			    inet_pton(AF_INET6, &host[1],
1648 				      &hid6.sin6_addr) == 1)
1649 			{
1650 				addr.sin6.sin6_family = AF_INET6;
1651 				addr.sin6.sin6_addr = hid6.sin6_addr;
1652 			}
1653 			else
1654 # endif /* NETINET6 */
1655 			{
1656 				/* try it as a host name (avoid MX lookup) */
1657 				hp = sm_gethostbyname(&host[1], family);
1658 				if (hp == NULL && p[-1] == '.')
1659 				{
1660 # if NAMED_BIND
1661 					int oldopts = _res.options;
1662 
1663 					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
1664 # endif /* NAMED_BIND */
1665 					p[-1] = '\0';
1666 					hp = sm_gethostbyname(&host[1],
1667 							      family);
1668 					p[-1] = '.';
1669 # if NAMED_BIND
1670 					_res.options = oldopts;
1671 # endif /* NAMED_BIND */
1672 				}
1673 				*p = ']';
1674 				goto gothostent;
1675 			}
1676 			*p = ']';
1677 		}
1678 		if (p == NULL)
1679 		{
1680 			extern char MsgBuf[];
1681 
1682 			usrerrenh("5.1.2",
1683 				  "553 Invalid numeric domain spec \"%s\"",
1684 				  host);
1685 			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
1686 			errno = EINVAL;
1687 			return EX_NOHOST;
1688 		}
1689 	}
1690 	else
1691 	{
1692 		/* contortion to get around SGI cc complaints */
1693 		{
1694 			p = &host[strlen(host) - 1];
1695 			hp = sm_gethostbyname(host, family);
1696 			if (hp == NULL && *p == '.')
1697 			{
1698 # if NAMED_BIND
1699 				int oldopts = _res.options;
1700 
1701 				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
1702 # endif /* NAMED_BIND */
1703 				*p = '\0';
1704 				hp = sm_gethostbyname(host, family);
1705 				*p = '.';
1706 # if NAMED_BIND
1707 				_res.options = oldopts;
1708 # endif /* NAMED_BIND */
1709 			}
1710 		}
1711 gothostent:
1712 		if (hp == NULL)
1713 		{
1714 # if NAMED_BIND
1715 			/* check for name server timeouts */
1716 			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
1717 			    (errno == ECONNREFUSED && UseNameServer))
1718 			{
1719 				save_errno = errno;
1720 				mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
1721 				errno = save_errno;
1722 				return EX_TEMPFAIL;
1723 			}
1724 # endif /* NAMED_BIND */
1725 # if NETINET6
1726 			/*
1727 			**  Try v6 first, then fall back to v4.
1728 			**  If we found a v6 address, but no v4
1729 			**  addresses, then TEMPFAIL.
1730 			*/
1731 
1732 			if (family == AF_INET6)
1733 			{
1734 				family = AF_INET;
1735 				goto v4retry;
1736 			}
1737 			if (v6found)
1738 				goto v6tempfail;
1739 # endif /* NETINET6 */
1740 			save_errno = errno;
1741 			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
1742 			errno = save_errno;
1743 			return EX_NOHOST;
1744 		}
1745 		addr.sa.sa_family = hp->h_addrtype;
1746 		switch (hp->h_addrtype)
1747 		{
1748 # if NETINET
1749 		  case AF_INET:
1750 			memmove(&addr.sin.sin_addr,
1751 				hp->h_addr,
1752 				INADDRSZ);
1753 			break;
1754 # endif /* NETINET */
1755 
1756 # if NETINET6
1757 		  case AF_INET6:
1758 			memmove(&addr.sin6.sin6_addr,
1759 				hp->h_addr,
1760 				IN6ADDRSZ);
1761 			break;
1762 # endif /* NETINET6 */
1763 
1764 		  default:
1765 			if (hp->h_length > sizeof addr.sa.sa_data)
1766 			{
1767 				syserr("makeconnection: long sa_data: family %d len %d",
1768 					hp->h_addrtype, hp->h_length);
1769 				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
1770 				errno = EINVAL;
1771 				return EX_NOHOST;
1772 			}
1773 			memmove(addr.sa.sa_data,
1774 				hp->h_addr,
1775 				hp->h_length);
1776 			break;
1777 		}
1778 		addrno = 1;
1779 	}
1780 
1781 	/*
1782 	**  Determine the port number.
1783 	*/
1784 
1785 	if (port == 0)
1786 	{
1787 # ifdef NO_GETSERVBYNAME
1788 		port = htons(25);
1789 # else /* NO_GETSERVBYNAME */
1790 		register struct servent *sp = getservbyname("smtp", "tcp");
1791 
1792 		if (sp == NULL)
1793 		{
1794 			if (LogLevel > 2)
1795 				sm_syslog(LOG_ERR, NOQID,
1796 					  "makeconnection: service \"smtp\" unknown");
1797 			port = htons(25);
1798 		}
1799 		else
1800 			port = sp->s_port;
1801 # endif /* NO_GETSERVBYNAME */
1802 	}
1803 
1804 	switch (addr.sa.sa_family)
1805 	{
1806 # if NETINET
1807 	  case AF_INET:
1808 		addr.sin.sin_port = port;
1809 		addrlen = sizeof (struct sockaddr_in);
1810 		break;
1811 # endif /* NETINET */
1812 
1813 # if NETINET6
1814 	  case AF_INET6:
1815 		addr.sin6.sin6_port = port;
1816 		addrlen = sizeof (struct sockaddr_in6);
1817 		break;
1818 # endif /* NETINET6 */
1819 
1820 # if NETISO
1821 	  case AF_ISO:
1822 		/* assume two byte transport selector */
1823 		memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
1824 		addrlen = sizeof (struct sockaddr_iso);
1825 		break;
1826 # endif /* NETISO */
1827 
1828 	  default:
1829 		syserr("Can't connect to address family %d", addr.sa.sa_family);
1830 		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
1831 		errno = EINVAL;
1832 		return EX_NOHOST;
1833 	}
1834 
1835 	/*
1836 	**  Try to actually open the connection.
1837 	*/
1838 
1839 # ifdef XLA
1840 	/* if too many connections, don't bother trying */
1841 	if (!xla_noqueue_ok(host))
1842 		return EX_TEMPFAIL;
1843 # endif /* XLA */
1844 
1845 	firstconnect = TRUE;
1846 	for (;;)
1847 	{
1848 		if (tTd(16, 1))
1849 			dprintf("makeconnection (%s [%s])\n",
1850 				host, anynet_ntoa(&addr));
1851 
1852 		/* save for logging */
1853 		CurHostAddr = addr;
1854 
1855 		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
1856 		{
1857 			int rport = IPPORT_RESERVED - 1;
1858 
1859 			s = rresvport(&rport);
1860 		}
1861 		else
1862 		{
1863 			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
1864 		}
1865 		if (s < 0)
1866 		{
1867 			save_errno = errno;
1868 			syserr("makeconnection: cannot create socket");
1869 # ifdef XLA
1870 			xla_host_end(host);
1871 # endif /* XLA */
1872 			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
1873 			errno = save_errno;
1874 			return EX_TEMPFAIL;
1875 		}
1876 
1877 # ifdef SO_SNDBUF
1878 		if (TcpSndBufferSize > 0)
1879 		{
1880 			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1881 				       (char *) &TcpSndBufferSize,
1882 				       sizeof(TcpSndBufferSize)) < 0)
1883 				syserr("makeconnection: setsockopt(SO_SNDBUF)");
1884 		}
1885 # endif /* SO_SNDBUF */
1886 # ifdef SO_RCVBUF
1887 		if (TcpRcvBufferSize > 0)
1888 		{
1889 			if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1890 				       (char *) &TcpRcvBufferSize,
1891 				       sizeof(TcpRcvBufferSize)) < 0)
1892 				syserr("makeconnection: setsockopt(SO_RCVBUF)");
1893 		}
1894 # endif /* SO_RCVBUF */
1895 
1896 
1897 		if (tTd(16, 1))
1898 			dprintf("makeconnection: fd=%d\n", s);
1899 
1900 		/* turn on network debugging? */
1901 		if (tTd(16, 101))
1902 		{
1903 			int on = 1;
1904 
1905 			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
1906 					  (char *)&on, sizeof on);
1907 		}
1908 		if (e->e_xfp != NULL)
1909 			(void) fflush(e->e_xfp);	/* for debugging */
1910 		errno = 0;				/* for debugging */
1911 
1912 		if (clt_bind)
1913 		{
1914 			int on = 1;
1915 
1916 			switch (clt_addr.sa.sa_family)
1917 			{
1918 # if NETINET
1919 			  case AF_INET:
1920 				if (clt_addr.sin.sin_port != 0)
1921 					(void) setsockopt(s, SOL_SOCKET,
1922 							  SO_REUSEADDR,
1923 							  (char *) &on,
1924 							  sizeof on);
1925 				break;
1926 # endif /* NETINET */
1927 
1928 # if NETINET6
1929 			  case AF_INET6:
1930 				if (clt_addr.sin6.sin6_port != 0)
1931 					(void) setsockopt(s, SOL_SOCKET,
1932 							  SO_REUSEADDR,
1933 							  (char *) &on,
1934 							  sizeof on);
1935 				break;
1936 # endif /* NETINET6 */
1937 			}
1938 
1939 			if (bind(s, &clt_addr.sa, socksize) < 0)
1940 			{
1941 				save_errno = errno;
1942 				(void) close(s);
1943 				errno = save_errno;
1944 				syserr("makeconnection: cannot bind socket [%s]",
1945 				       anynet_ntoa(&clt_addr));
1946 				errno = save_errno;
1947 				return EX_TEMPFAIL;
1948 			}
1949 		}
1950 
1951 		/*
1952 		**  Linux seems to hang in connect for 90 minutes (!!!).
1953 		**  Time out the connect to avoid this problem.
1954 		*/
1955 
1956 		if (setjmp(CtxConnectTimeout) == 0)
1957 		{
1958 			int i;
1959 
1960 			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
1961 				ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
1962 			else if (TimeOuts.to_connect != 0)
1963 				ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
1964 			else
1965 				ev = NULL;
1966 
1967 			switch (ConnectOnlyTo.sa.sa_family)
1968 			{
1969 # if NETINET
1970 			  case AF_INET:
1971 				addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
1972 				break;
1973 # endif /* NETINET */
1974 
1975 # if NETINET6
1976 			  case AF_INET6:
1977 				memmove(&addr.sin6.sin6_addr,
1978 					&ConnectOnlyTo.sin6.sin6_addr,
1979 					IN6ADDRSZ);
1980 				break;
1981 # endif /* NETINET6 */
1982 			}
1983 			i = connect(s, (struct sockaddr *) &addr, addrlen);
1984 			save_errno = errno;
1985 			if (ev != NULL)
1986 				clrevent(ev);
1987 			if (i >= 0)
1988 				break;
1989 		}
1990 		else
1991 			save_errno = errno;
1992 
1993 		/* if running demand-dialed connection, try again */
1994 		if (DialDelay > 0 && firstconnect)
1995 		{
1996 			if (tTd(16, 1))
1997 				dprintf("Connect failed (%s); trying again...\n",
1998 					errstring(save_errno));
1999 			firstconnect = FALSE;
2000 			(void) sleep(DialDelay);
2001 			continue;
2002 		}
2003 
2004 		/* couldn't connect.... figure out why */
2005 		(void) close(s);
2006 
2007 		if (LogLevel >= 14)
2008 			sm_syslog(LOG_INFO, e->e_id,
2009 				  "makeconnection (%s [%s]) failed: %s",
2010 				  host, anynet_ntoa(&addr),
2011 				  errstring(save_errno));
2012 
2013 		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
2014 		{
2015 			if (tTd(16, 1))
2016 				dprintf("Connect failed (%s); trying new address....\n",
2017 					errstring(save_errno));
2018 			switch (addr.sa.sa_family)
2019 			{
2020 # if NETINET
2021 			  case AF_INET:
2022 				memmove(&addr.sin.sin_addr,
2023 					hp->h_addr_list[addrno++],
2024 					INADDRSZ);
2025 				break;
2026 # endif /* NETINET */
2027 
2028 # if NETINET6
2029 			  case AF_INET6:
2030 				memmove(&addr.sin6.sin6_addr,
2031 					hp->h_addr_list[addrno++],
2032 					IN6ADDRSZ);
2033 				break;
2034 # endif /* NETINET6 */
2035 
2036 			  default:
2037 				memmove(addr.sa.sa_data,
2038 					hp->h_addr_list[addrno++],
2039 					hp->h_length);
2040 				break;
2041 			}
2042 			continue;
2043 		}
2044 		errno = save_errno;
2045 
2046 # if NETINET6
2047 		if (family == AF_INET6)
2048 		{
2049 			if (tTd(16, 1))
2050 				dprintf("Connect failed (%s); retrying with AF_INET....\n",
2051 					errstring(save_errno));
2052 			v6found = TRUE;
2053 			family = AF_INET;
2054 			goto v4retry;
2055 		}
2056 	v6tempfail:
2057 # endif /* NETINET6 */
2058 		/* couldn't open connection */
2059 # if NETINET6
2060 		/* Don't clobber an already saved errno from v4retry */
2061 		if (errno > 0)
2062 # endif /* NETINET6 */
2063 			save_errno = errno;
2064 		if (tTd(16, 1))
2065 			dprintf("Connect failed (%s)\n", errstring(save_errno));
2066 # ifdef XLA
2067 		xla_host_end(host);
2068 # endif /* XLA */
2069 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2070 		errno = save_errno;
2071 		return EX_TEMPFAIL;
2072 	}
2073 
2074 	/* connection ok, put it into canonical form */
2075 	mci->mci_out = NULL;
2076 	if ((mci->mci_out = fdopen(s, "w")) == NULL ||
2077 	    (s = dup(s)) < 0 ||
2078 	    (mci->mci_in = fdopen(s, "r")) == NULL)
2079 	{
2080 		save_errno = errno;
2081 		syserr("cannot open SMTP client channel, fd=%d", s);
2082 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2083 		if (mci->mci_out != NULL)
2084 			(void) fclose(mci->mci_out);
2085 		(void) close(s);
2086 		errno = save_errno;
2087 		return EX_TEMPFAIL;
2088 	}
2089 
2090 	/* find out name for Interface through which we connect */
2091 	len = sizeof addr;
2092 	if (getsockname(s, &addr.sa, &len) == 0)
2093 	{
2094 		char *name;
2095 		char *p;
2096 
2097 		define(macid("{if_addr}", NULL), newstr(anynet_ntoa(&addr)),
2098 		       &BlankEnvelope);
2099 		p = xalloc(5);
2100 		snprintf(p, 4, "%d", addr.sa.sa_family);
2101 		define(macid("{if_family}", NULL), p, &BlankEnvelope);
2102 
2103 		name = hostnamebyanyaddr(&addr);
2104 		define(macid("{if_name}", NULL), newstr(name), &BlankEnvelope);
2105 		if (LogLevel > 11)
2106 		{
2107 			/* log connection information */
2108 			sm_syslog(LOG_INFO, e->e_id,
2109 				  "SMTP outgoing connect on %.40s", name);
2110 		}
2111 		if (bitnset(D_IFNHELO, d_flags))
2112 		{
2113 			if (name[0] != '[' && strchr(name, '.') != NULL)
2114 				mci->mci_heloname = newstr(name);
2115 		}
2116 	}
2117 	else
2118 	{
2119 		define(macid("{if_name}", NULL), NULL, &BlankEnvelope);
2120 		define(macid("{if_addr}", NULL), NULL, &BlankEnvelope);
2121 		define(macid("{if_family}", NULL), NULL, &BlankEnvelope);
2122 	}
2123 	mci_setstat(mci, EX_OK, NULL, NULL);
2124 	return EX_OK;
2125 }
2126 
2127 static void
2128 connecttimeout()
2129 {
2130 	errno = ETIMEDOUT;
2131 	longjmp(CtxConnectTimeout, 1);
2132 }
2133 /*
2134 **  MAKECONNECTION_DS -- make a connection to a domain socket.
2135 **
2136 **	Parameters:
2137 **		mux_path -- the path of the socket to connect to.
2138 **		mci -- a pointer to the mail connection information
2139 **			structure to be filled in.
2140 **
2141 **	Returns:
2142 **		An exit code telling whether the connection could be
2143 **			made and if not why not.
2144 **
2145 **	Side Effects:
2146 **		none.
2147 */
2148 
2149 # if NETUNIX
2150 int makeconnection_ds(mux_path, mci)
2151 	char *mux_path;
2152 	register MCI *mci;
2153 {
2154 	int sock;
2155 	int rval, save_errno;
2156 	long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
2157 	struct sockaddr_un unix_addr;
2158 
2159 	/* if not safe, don't connect */
2160 	rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
2161 			sff, S_IRUSR|S_IWUSR, NULL);
2162 
2163 	if (rval != 0)
2164 	{
2165 		syserr("makeconnection_ds: unsafe domain socket");
2166 		mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
2167 		errno = rval;
2168 		return EX_TEMPFAIL;
2169 	}
2170 
2171 	/* prepare address structure */
2172 	memset(&unix_addr, '\0', sizeof unix_addr);
2173 	unix_addr.sun_family = AF_UNIX;
2174 
2175 	if (strlen(mux_path) >= sizeof unix_addr.sun_path)
2176 	{
2177 		syserr("makeconnection_ds: domain socket name too long");
2178 		/* XXX why TEMPFAIL ? */
2179 		mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
2180 		errno = ENAMETOOLONG;
2181 		return EX_UNAVAILABLE;
2182 	}
2183 	(void) strlcpy(unix_addr.sun_path, mux_path, sizeof unix_addr.sun_path);
2184 
2185 	/* initialize domain socket */
2186 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
2187 	if (sock == -1)
2188 	{
2189 		save_errno = errno;
2190 		syserr("makeconnection_ds: could not create domain socket");
2191 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2192 		errno = save_errno;
2193 		return EX_TEMPFAIL;
2194 	}
2195 
2196 	/* connect to server */
2197 	if (connect(sock, (struct sockaddr *) &unix_addr,
2198 		    sizeof(unix_addr)) == -1)
2199 	{
2200 		save_errno = errno;
2201 		syserr("Could not connect to socket %s", mux_path);
2202 		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2203 		(void) close(sock);
2204 		errno = save_errno;
2205 		return EX_TEMPFAIL;
2206 	}
2207 
2208 	/* connection ok, put it into canonical form */
2209 	mci->mci_out = NULL;
2210 	if ((mci->mci_out = fdopen(sock, "w")) == NULL ||
2211 	    (sock = dup(sock)) < 0 ||
2212 	    (mci->mci_in = fdopen(sock, "r")) == NULL)
2213 	{
2214 		save_errno = errno;
2215 		syserr("cannot open SMTP client channel, fd=%d", sock);
2216 		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2217 		if (mci->mci_out != NULL)
2218 			(void) fclose(mci->mci_out);
2219 		(void) close(sock);
2220 		errno = save_errno;
2221 		return EX_TEMPFAIL;
2222 	}
2223 
2224 	mci_setstat(mci, EX_OK, NULL, NULL);
2225 	errno = 0;
2226 	return EX_OK;
2227 }
2228 # endif /* NETUNIX */
2229 /*
2230 **  MYHOSTNAME -- return the name of this host.
2231 **
2232 **	Parameters:
2233 **		hostbuf -- a place to return the name of this host.
2234 **		size -- the size of hostbuf.
2235 **
2236 **	Returns:
2237 **		A list of aliases for this host.
2238 **
2239 **	Side Effects:
2240 **		Adds numeric codes to $=w.
2241 */
2242 
2243 struct hostent *
2244 myhostname(hostbuf, size)
2245 	char hostbuf[];
2246 	int size;
2247 {
2248 	register struct hostent *hp;
2249 
2250 	if (gethostname(hostbuf, size) < 0)
2251 	{
2252 		(void) strlcpy(hostbuf, "localhost", size);
2253 	}
2254 	hp = sm_gethostbyname(hostbuf, InetMode);
2255 	if (hp == NULL)
2256 		return NULL;
2257 	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
2258 		(void) cleanstrcpy(hostbuf, hp->h_name, size);
2259 
2260 # if NETINFO
2261 	if (strchr(hostbuf, '.') == NULL)
2262 	{
2263 		char *domainname;
2264 
2265 		domainname = ni_propval("/locations", NULL, "resolver",
2266 					"domain", '\0');
2267 		if (domainname != NULL &&
2268 		    strlen(domainname) + strlen(hostbuf) + 1 < size)
2269 		{
2270 			(void) strlcat(hostbuf, ".", size);
2271 			(void) strlcat(hostbuf, domainname, size);
2272 		}
2273 	}
2274 # endif /* NETINFO */
2275 
2276 	/*
2277 	**  If there is still no dot in the name, try looking for a
2278 	**  dotted alias.
2279 	*/
2280 
2281 	if (strchr(hostbuf, '.') == NULL)
2282 	{
2283 		char **ha;
2284 
2285 		for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
2286 		{
2287 			if (strchr(*ha, '.') != NULL)
2288 			{
2289 				(void) cleanstrcpy(hostbuf, *ha, size - 1);
2290 				hostbuf[size - 1] = '\0';
2291 				break;
2292 			}
2293 		}
2294 	}
2295 
2296 	/*
2297 	**  If _still_ no dot, wait for a while and try again -- it is
2298 	**  possible that some service is starting up.  This can result
2299 	**  in excessive delays if the system is badly configured, but
2300 	**  there really isn't a way around that, particularly given that
2301 	**  the config file hasn't been read at this point.
2302 	**  All in all, a bit of a mess.
2303 	*/
2304 
2305 	if (strchr(hostbuf, '.') == NULL &&
2306 	    !getcanonname(hostbuf, size, TRUE))
2307 	{
2308 		sm_syslog(LOG_CRIT, NOQID,
2309 			  "My unqualified host name (%s) unknown; sleeping for retry",
2310 			  hostbuf);
2311 		message("My unqualified host name (%s) unknown; sleeping for retry",
2312 			hostbuf);
2313 		(void) sleep(60);
2314 		if (!getcanonname(hostbuf, size, TRUE))
2315 		{
2316 			sm_syslog(LOG_ALERT, NOQID,
2317 				  "unable to qualify my own domain name (%s) -- using short name",
2318 				  hostbuf);
2319 			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
2320 				hostbuf);
2321 		}
2322 	}
2323 	return hp;
2324 }
2325 /*
2326 **  ADDRCMP -- compare two host addresses
2327 **
2328 **	Parameters:
2329 **		hp -- hostent structure for the first address
2330 **		ha -- actual first address
2331 **		sa -- second address
2332 **
2333 **	Returns:
2334 **		0 -- if ha and sa match
2335 **		else -- they don't match
2336 */
2337 
2338 static int
2339 addrcmp(hp, ha, sa)
2340 	struct hostent *hp;
2341 	char *ha;
2342 	SOCKADDR *sa;
2343 {
2344 # if NETINET6
2345 	u_char *a;
2346 # endif /* NETINET6 */
2347 
2348 	switch (sa->sa.sa_family)
2349 	{
2350 # if NETINET
2351 	  case AF_INET:
2352 		if (hp->h_addrtype == AF_INET)
2353 			return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
2354 		break;
2355 # endif /* NETINET */
2356 
2357 # if NETINET6
2358 	  case AF_INET6:
2359 		a = (u_char *) &sa->sin6.sin6_addr;
2360 
2361 		/* Straight binary comparison */
2362 		if (hp->h_addrtype == AF_INET6)
2363 			return memcmp(ha, a, IN6ADDRSZ);
2364 
2365 		/* If IPv4-mapped IPv6 address, compare the IPv4 section */
2366 		if (hp->h_addrtype == AF_INET &&
2367 		    IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
2368 			return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
2369 		break;
2370 # endif /* NETINET6 */
2371 	}
2372 	return -1;
2373 }
2374 /*
2375 **  GETAUTHINFO -- get the real host name associated with a file descriptor
2376 **
2377 **	Uses RFC1413 protocol to try to get info from the other end.
2378 **
2379 **	Parameters:
2380 **		fd -- the descriptor
2381 **		may_be_forged -- an outage that is set to TRUE if the
2382 **			forward lookup of RealHostName does not match
2383 **			RealHostAddr; set to FALSE if they do match.
2384 **
2385 **	Returns:
2386 **		The user@host information associated with this descriptor.
2387 */
2388 
2389 static jmp_buf	CtxAuthTimeout;
2390 
2391 static void
2392 authtimeout()
2393 {
2394 	longjmp(CtxAuthTimeout, 1);
2395 }
2396 
2397 char *
2398 getauthinfo(fd, may_be_forged)
2399 	int fd;
2400 	bool *may_be_forged;
2401 {
2402 	u_short port = 0;
2403 	SOCKADDR_LEN_T falen;
2404 	register char *volatile p = NULL;
2405 	SOCKADDR la;
2406 	SOCKADDR_LEN_T lalen;
2407 	register struct servent *sp;
2408 	volatile int s;
2409 	int i = 0;
2410 	EVENT *ev;
2411 	int nleft;
2412 	struct hostent *hp;
2413 	char *ostype = NULL;
2414 	char **ha;
2415 	char ibuf[MAXNAME + 1];
2416 	static char hbuf[MAXNAME * 2 + 11];
2417 
2418 	*may_be_forged = FALSE;
2419 	falen = sizeof RealHostAddr;
2420 	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
2421 	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
2422 	{
2423 		if (i < 0)
2424 		{
2425 			/*
2426 			**  ENOTSOCK is OK: bail on anything else, but reset
2427 			**  errno in this case, so a mis-report doesn't
2428 			**  happen later.
2429 			*/
2430 			if (errno != ENOTSOCK)
2431 				return NULL;
2432 			errno = 0;
2433 		}
2434 		(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
2435 			RealUserName);
2436 		if (tTd(9, 1))
2437 			dprintf("getauthinfo: %s\n", hbuf);
2438 		return hbuf;
2439 	}
2440 
2441 	if (RealHostName == NULL)
2442 	{
2443 		/* translate that to a host name */
2444 		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
2445 		if (strlen(RealHostName) > MAXNAME)
2446 			RealHostName[MAXNAME] = '\0';
2447 	}
2448 
2449 	/* cross check RealHostName with forward DNS lookup */
2450 	if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
2451 	    RealHostName[0] == '[')
2452 	{
2453 		/*
2454 		**  address is not a socket or have an
2455 		**  IP address with no forward lookup
2456 		*/
2457 		*may_be_forged = FALSE;
2458 	}
2459 	else
2460 	{
2461 		/* try to match the reverse against the forward lookup */
2462 		hp = sm_gethostbyname(RealHostName,
2463 				      RealHostAddr.sa.sa_family);
2464 
2465 		if (hp == NULL)
2466 			*may_be_forged = TRUE;
2467 		else
2468 		{
2469 			for (ha = hp->h_addr_list; *ha != NULL; ha++)
2470 				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
2471 					break;
2472 			*may_be_forged = *ha == NULL;
2473 		}
2474 	}
2475 
2476 	if (TimeOuts.to_ident == 0)
2477 		goto noident;
2478 
2479 	lalen = sizeof la;
2480 	switch (RealHostAddr.sa.sa_family)
2481 	{
2482 # if NETINET
2483 	  case AF_INET:
2484 		if (getsockname(fd, &la.sa, &lalen) < 0 ||
2485 		    lalen <= 0 ||
2486 		    la.sa.sa_family != AF_INET)
2487 		{
2488 			/* no ident info */
2489 			goto noident;
2490 		}
2491 		port = RealHostAddr.sin.sin_port;
2492 
2493 		/* create ident query */
2494 		(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
2495 				ntohs(RealHostAddr.sin.sin_port),
2496 				ntohs(la.sin.sin_port));
2497 
2498 		/* create local address */
2499 		la.sin.sin_port = 0;
2500 
2501 		/* create foreign address */
2502 #  ifdef NO_GETSERVBYNAME
2503 		RealHostAddr.sin.sin_port = htons(113);
2504 #  else /* NO_GETSERVBYNAME */
2505 		sp = getservbyname("auth", "tcp");
2506 		if (sp != NULL)
2507 			RealHostAddr.sin.sin_port = sp->s_port;
2508 		else
2509 			RealHostAddr.sin.sin_port = htons(113);
2510 		break;
2511 #  endif /* NO_GETSERVBYNAME */
2512 # endif /* NETINET */
2513 
2514 # if NETINET6
2515 	  case AF_INET6:
2516 		if (getsockname(fd, &la.sa, &lalen) < 0 ||
2517 		    lalen <= 0 ||
2518 		    la.sa.sa_family != AF_INET6)
2519 		{
2520 			/* no ident info */
2521 			goto noident;
2522 		}
2523 		port = RealHostAddr.sin6.sin6_port;
2524 
2525 		/* create ident query */
2526 		(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
2527 				ntohs(RealHostAddr.sin6.sin6_port),
2528 				ntohs(la.sin6.sin6_port));
2529 
2530 		/* create local address */
2531 		la.sin6.sin6_port = 0;
2532 
2533 		/* create foreign address */
2534 #  ifdef NO_GETSERVBYNAME
2535 		RealHostAddr.sin6.sin6_port = htons(113);
2536 #  else /* NO_GETSERVBYNAME */
2537 		sp = getservbyname("auth", "tcp");
2538 		if (sp != NULL)
2539 			RealHostAddr.sin6.sin6_port = sp->s_port;
2540 		else
2541 			RealHostAddr.sin6.sin6_port = htons(113);
2542 		break;
2543 #  endif /* NO_GETSERVBYNAME */
2544 # endif /* NETINET6 */
2545 	  default:
2546 		/* no ident info */
2547 		goto noident;
2548 	}
2549 
2550 	s = -1;
2551 	if (setjmp(CtxAuthTimeout) != 0)
2552 	{
2553 		if (s >= 0)
2554 			(void) close(s);
2555 		goto noident;
2556 	}
2557 
2558 	/* put a timeout around the whole thing */
2559 	ev = setevent(TimeOuts.to_ident, authtimeout, 0);
2560 
2561 
2562 	/* connect to foreign IDENT server using same address as SMTP socket */
2563 	s = socket(la.sa.sa_family, SOCK_STREAM, 0);
2564 	if (s < 0)
2565 	{
2566 		clrevent(ev);
2567 		goto noident;
2568 	}
2569 	if (bind(s, &la.sa, lalen) < 0 ||
2570 	    connect(s, &RealHostAddr.sa, lalen) < 0)
2571 	{
2572 		goto closeident;
2573 	}
2574 
2575 	if (tTd(9, 10))
2576 		dprintf("getauthinfo: sent %s", ibuf);
2577 
2578 	/* send query */
2579 	if (write(s, ibuf, strlen(ibuf)) < 0)
2580 		goto closeident;
2581 
2582 	/* get result */
2583 	p = &ibuf[0];
2584 	nleft = sizeof ibuf - 1;
2585 	while ((i = read(s, p, nleft)) > 0)
2586 	{
2587 		p += i;
2588 		nleft -= i;
2589 		*p = '\0';
2590 		if (strchr(ibuf, '\n') != NULL)
2591 			break;
2592 	}
2593 	(void) close(s);
2594 	clrevent(ev);
2595 	if (i < 0 || p == &ibuf[0])
2596 		goto noident;
2597 
2598 	if (*--p == '\n' && *--p == '\r')
2599 		p--;
2600 	*++p = '\0';
2601 
2602 	if (tTd(9, 3))
2603 		dprintf("getauthinfo:  got %s\n", ibuf);
2604 
2605 	/* parse result */
2606 	p = strchr(ibuf, ':');
2607 	if (p == NULL)
2608 	{
2609 		/* malformed response */
2610 		goto noident;
2611 	}
2612 	while (isascii(*++p) && isspace(*p))
2613 		continue;
2614 	if (strncasecmp(p, "userid", 6) != 0)
2615 	{
2616 		/* presumably an error string */
2617 		goto noident;
2618 	}
2619 	p += 6;
2620 	while (isascii(*p) && isspace(*p))
2621 		p++;
2622 	if (*p++ != ':')
2623 	{
2624 		/* either useridxx or malformed response */
2625 		goto noident;
2626 	}
2627 
2628 	/* p now points to the OSTYPE field */
2629 	while (isascii(*p) && isspace(*p))
2630 		p++;
2631 	ostype = p;
2632 	p = strchr(p, ':');
2633 	if (p == NULL)
2634 	{
2635 		/* malformed response */
2636 		goto noident;
2637 	}
2638 	else
2639 	{
2640 		char *charset;
2641 
2642 		*p = '\0';
2643 		charset = strchr(ostype, ',');
2644 		if (charset != NULL)
2645 			*charset = '\0';
2646 	}
2647 
2648 	/* 1413 says don't do this -- but it's broken otherwise */
2649 	while (isascii(*++p) && isspace(*p))
2650 		continue;
2651 
2652 	/* p now points to the authenticated name -- copy carefully */
2653 	if (strncasecmp(ostype, "other", 5) == 0 &&
2654 	    (ostype[5] == ' ' || ostype[5] == '\0'))
2655 	{
2656 		snprintf(hbuf, sizeof hbuf, "IDENT:");
2657 		cleanstrcpy(&hbuf[6], p, MAXNAME);
2658 	}
2659 	else
2660 		cleanstrcpy(hbuf, p, MAXNAME);
2661 	i = strlen(hbuf);
2662 	snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
2663 		 RealHostName == NULL ? "localhost" : RealHostName);
2664 	goto postident;
2665 
2666 closeident:
2667 	(void) close(s);
2668 	clrevent(ev);
2669 
2670 noident:
2671 	/* put back the original incoming port */
2672 	switch (RealHostAddr.sa.sa_family)
2673 	{
2674 # if NETINET
2675 	  case AF_INET:
2676 		if (port > 0)
2677 			RealHostAddr.sin.sin_port = port;
2678 		break;
2679 # endif /* NETINET */
2680 
2681 # if NETINET6
2682 	  case AF_INET6:
2683 		if (port > 0)
2684 			RealHostAddr.sin6.sin6_port = port;
2685 		break;
2686 # endif /* NETINET6 */
2687 	}
2688 
2689 	if (RealHostName == NULL)
2690 	{
2691 		if (tTd(9, 1))
2692 			dprintf("getauthinfo: NULL\n");
2693 		return NULL;
2694 	}
2695 	snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
2696 
2697 postident:
2698 # if IP_SRCROUTE
2699 #  ifndef GET_IPOPT_DST
2700 #   define GET_IPOPT_DST(dst)	(dst)
2701 #  endif /* ! GET_IPOPT_DST */
2702 	/*
2703 	**  Extract IP source routing information.
2704 	**
2705 	**	Format of output for a connection from site a through b
2706 	**	through c to d:
2707 	**		loose:      @site-c@site-b:site-a
2708 	**		strict:	   !@site-c@site-b:site-a
2709 	**
2710 	**	o - pointer within ipopt_list structure.
2711 	**	q - pointer within ls/ss rr route data
2712 	**	p - pointer to hbuf
2713 	*/
2714 
2715 	if (RealHostAddr.sa.sa_family == AF_INET)
2716 	{
2717 		SOCKOPT_LEN_T ipoptlen;
2718 		int j;
2719 		u_char *q;
2720 		u_char *o;
2721 		int l;
2722 		struct IPOPTION ipopt;
2723 
2724 		ipoptlen = sizeof ipopt;
2725 		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
2726 			       (char *) &ipopt, &ipoptlen) < 0)
2727 			goto noipsr;
2728 		if (ipoptlen == 0)
2729 			goto noipsr;
2730 		o = (u_char *) ipopt.IP_LIST;
2731 		while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
2732 		{
2733 			switch (*o)
2734 			{
2735 			  case IPOPT_EOL:
2736 				o = NULL;
2737 				break;
2738 
2739 			  case IPOPT_NOP:
2740 				o++;
2741 				break;
2742 
2743 			  case IPOPT_SSRR:
2744 			  case IPOPT_LSRR:
2745 				/*
2746 				**  Source routing.
2747 				**	o[0] is the option type (loose/strict).
2748 				**	o[1] is the length of this option,
2749 				**		including option type and
2750 				**		length.
2751 				**	o[2] is the pointer into the route
2752 				**		data.
2753 				**	o[3] begins the route data.
2754 				*/
2755 
2756 				p = &hbuf[strlen(hbuf)];
2757 				l = sizeof hbuf - (hbuf - p) - 6;
2758 				snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
2759 				    *o == IPOPT_SSRR ? "!" : "",
2760 				    l > 240 ? 120 : l / 2,
2761 				    inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
2762 				i = strlen(p);
2763 				p += i;
2764 				l -= strlen(p);
2765 
2766 				j = o[1] / sizeof(struct in_addr) - 1;
2767 
2768 				/* q skips length and router pointer to data */
2769 				q = &o[3];
2770 				for ( ; j >= 0; j--)
2771 				{
2772 					struct in_addr addr;
2773 
2774 					memcpy(&addr, q, sizeof(addr));
2775 					snprintf(p, SPACELEFT(hbuf, p),
2776 						 "%c%.*s",
2777 						 j != 0 ? '@' : ':',
2778 						 l > 240 ? 120 :
2779 						 j == 0 ? l : l / 2,
2780 						 inet_ntoa(addr));
2781 					i = strlen(p);
2782 					p += i;
2783 					l -= i + 1;
2784 					q += sizeof(struct in_addr);
2785 				}
2786 				o += o[1];
2787 				break;
2788 
2789 			  default:
2790 				/* Skip over option */
2791 				o += o[1];
2792 				break;
2793 			}
2794 		}
2795 		snprintf(p, SPACELEFT(hbuf, p), "]");
2796 		goto postipsr;
2797 	}
2798 
2799 noipsr:
2800 # endif /* IP_SRCROUTE */
2801 	if (RealHostName != NULL && RealHostName[0] != '[')
2802 	{
2803 		p = &hbuf[strlen(hbuf)];
2804 		(void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
2805 			anynet_ntoa(&RealHostAddr));
2806 	}
2807 	if (*may_be_forged)
2808 	{
2809 		p = &hbuf[strlen(hbuf)];
2810 		(void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
2811 	}
2812 
2813 # if IP_SRCROUTE
2814 postipsr:
2815 # endif /* IP_SRCROUTE */
2816 	if (tTd(9, 1))
2817 		dprintf("getauthinfo: %s\n", hbuf);
2818 
2819 	/* put back the original incoming port */
2820 	switch (RealHostAddr.sa.sa_family)
2821 	{
2822 # if NETINET
2823 	  case AF_INET:
2824 		if (port > 0)
2825 			RealHostAddr.sin.sin_port = port;
2826 		break;
2827 # endif /* NETINET */
2828 
2829 # if NETINET6
2830 	  case AF_INET6:
2831 		if (port > 0)
2832 			RealHostAddr.sin6.sin6_port = port;
2833 		break;
2834 # endif /* NETINET6 */
2835 	}
2836 
2837 	return hbuf;
2838 }
2839 /*
2840 **  HOST_MAP_LOOKUP -- turn a hostname into canonical form
2841 **
2842 **	Parameters:
2843 **		map -- a pointer to this map.
2844 **		name -- the (presumably unqualified) hostname.
2845 **		av -- unused -- for compatibility with other mapping
2846 **			functions.
2847 **		statp -- an exit status (out parameter) -- set to
2848 **			EX_TEMPFAIL if the name server is unavailable.
2849 **
2850 **	Returns:
2851 **		The mapping, if found.
2852 **		NULL if no mapping found.
2853 **
2854 **	Side Effects:
2855 **		Looks up the host specified in hbuf.  If it is not
2856 **		the canonical name for that host, return the canonical
2857 **		name (unless MF_MATCHONLY is set, which will cause the
2858 **		status only to be returned).
2859 */
2860 
2861 char *
2862 host_map_lookup(map, name, av, statp)
2863 	MAP *map;
2864 	char *name;
2865 	char **av;
2866 	int *statp;
2867 {
2868 	register struct hostent *hp;
2869 # if NETINET
2870 	struct in_addr in_addr;
2871 # endif /* NETINET */
2872 # if NETINET6
2873 	struct in6_addr in6_addr;
2874 # endif /* NETINET6 */
2875 	char *cp, *ans = NULL;
2876 	register STAB *s;
2877 	char hbuf[MAXNAME + 1];
2878 
2879 	/*
2880 	**  See if we have already looked up this name.  If so, just
2881 	**  return it.
2882 	*/
2883 
2884 	s = stab(name, ST_NAMECANON, ST_ENTER);
2885 	if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
2886 	{
2887 		if (tTd(9, 1))
2888 			dprintf("host_map_lookup(%s) => CACHE %s\n",
2889 				name,
2890 				s->s_namecanon.nc_cname == NULL
2891 					? "NULL"
2892 					: s->s_namecanon.nc_cname);
2893 		errno = s->s_namecanon.nc_errno;
2894 # if NAMED_BIND
2895 		h_errno = s->s_namecanon.nc_herrno;
2896 # endif /* NAMED_BIND */
2897 		*statp = s->s_namecanon.nc_stat;
2898 		if (*statp == EX_TEMPFAIL)
2899 		{
2900 			CurEnv->e_status = "4.4.3";
2901 			message("851 %s: Name server timeout",
2902 				shortenstring(name, 33));
2903 		}
2904 		if (*statp != EX_OK)
2905 			return NULL;
2906 		if (s->s_namecanon.nc_cname == NULL)
2907 		{
2908 			syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
2909 			       name,
2910 			       s->s_namecanon.nc_errno,
2911 			       s->s_namecanon.nc_herrno);
2912 			return NULL;
2913 		}
2914 		if (bitset(MF_MATCHONLY, map->map_mflags))
2915 			cp = map_rewrite(map, name, strlen(name), NULL);
2916 		else
2917 			cp = map_rewrite(map,
2918 					 s->s_namecanon.nc_cname,
2919 					 strlen(s->s_namecanon.nc_cname),
2920 					 av);
2921 		return cp;
2922 	}
2923 
2924 	/*
2925 	**  If we are running without a regular network connection (usually
2926 	**  dial-on-demand) and we are just queueing, we want to avoid DNS
2927 	**  lookups because those could try to connect to a server.
2928 	*/
2929 
2930 	if (CurEnv->e_sendmode == SM_DEFER &&
2931 	    bitset(MF_DEFER, map->map_mflags))
2932 	{
2933 		if (tTd(9, 1))
2934 			dprintf("host_map_lookup(%s) => DEFERRED\n", name);
2935 		*statp = EX_TEMPFAIL;
2936 		return NULL;
2937 	}
2938 
2939 	/*
2940 	**  If first character is a bracket, then it is an address
2941 	**  lookup.  Address is copied into a temporary buffer to
2942 	**  strip the brackets and to preserve name if address is
2943 	**  unknown.
2944 	*/
2945 
2946 	if (tTd(9, 1))
2947 		dprintf("host_map_lookup(%s) => ", name);
2948 	if (*name != '[')
2949 	{
2950 		snprintf(hbuf, sizeof hbuf, "%s", name);
2951 		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
2952 			ans = hbuf;
2953 	}
2954 	else
2955 	{
2956 		if ((cp = strchr(name, ']')) == NULL)
2957 			return NULL;
2958 		*cp = '\0';
2959 
2960 		hp = NULL;
2961 # if NETINET
2962 		if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
2963 			hp = sm_gethostbyaddr((char *)&in_addr,
2964 					      INADDRSZ, AF_INET);
2965 # endif /* NETINET */
2966 # if NETINET6
2967 		if (hp == NULL &&
2968 		    inet_pton(AF_INET6, &name[1], &in6_addr) == 1)
2969 			hp = sm_gethostbyaddr((char *)&in6_addr,
2970 					      IN6ADDRSZ, AF_INET6);
2971 # endif /* NETINET6 */
2972 		*cp = ']';
2973 
2974 		if (hp != NULL)
2975 		{
2976 			/* found a match -- copy out */
2977 			ans = denlstring((char *) hp->h_name, TRUE, TRUE);
2978 		}
2979 	}
2980 
2981 	s->s_namecanon.nc_flags |= NCF_VALID;	/* will be soon */
2982 
2983 	/* Found an answer */
2984 	if (ans != NULL)
2985 	{
2986 		s->s_namecanon.nc_stat = *statp = EX_OK;
2987 		s->s_namecanon.nc_cname = newstr(ans);
2988 		if (bitset(MF_MATCHONLY, map->map_mflags))
2989 			cp = map_rewrite(map, name, strlen(name), NULL);
2990 		else
2991 			cp = map_rewrite(map, ans, strlen(ans), av);
2992 		return cp;
2993 	}
2994 
2995 
2996 	/* No match found */
2997 	s->s_namecanon.nc_errno = errno;
2998 # if NAMED_BIND
2999 	s->s_namecanon.nc_herrno = h_errno;
3000 	if (tTd(9, 1))
3001 		dprintf("FAIL (%d)\n", h_errno);
3002 	switch (h_errno)
3003 	{
3004 	  case TRY_AGAIN:
3005 		if (UseNameServer)
3006 		{
3007 			CurEnv->e_status = "4.4.3";
3008 			message("851 %s: Name server timeout",
3009 				shortenstring(name, 33));
3010 		}
3011 		*statp = EX_TEMPFAIL;
3012 		break;
3013 
3014 	  case HOST_NOT_FOUND:
3015 	  case NO_DATA:
3016 		*statp = EX_NOHOST;
3017 		break;
3018 
3019 	  case NO_RECOVERY:
3020 		*statp = EX_SOFTWARE;
3021 		break;
3022 
3023 	  default:
3024 		*statp = EX_UNAVAILABLE;
3025 		break;
3026 	}
3027 # else /* NAMED_BIND */
3028 	if (tTd(9, 1))
3029 		dprintf("FAIL\n");
3030 	*statp = EX_NOHOST;
3031 # endif /* NAMED_BIND */
3032 	s->s_namecanon.nc_stat = *statp;
3033 	return NULL;
3034 }
3035 #else /* DAEMON */
3036 /* code for systems without sophisticated networking */
3037 
3038 /*
3039 **  MYHOSTNAME -- stub version for case of no daemon code.
3040 **
3041 **	Can't convert to upper case here because might be a UUCP name.
3042 **
3043 **	Mark, you can change this to be anything you want......
3044 */
3045 
3046 char **
3047 myhostname(hostbuf, size)
3048 	char hostbuf[];
3049 	int size;
3050 {
3051 	register FILE *f;
3052 
3053 	hostbuf[0] = '\0';
3054 	f = fopen("/usr/include/whoami", "r");
3055 	if (f != NULL)
3056 	{
3057 		(void) fgets(hostbuf, size, f);
3058 		fixcrlf(hostbuf, TRUE);
3059 		(void) fclose(f);
3060 	}
3061 	return NULL;
3062 }
3063 /*
3064 **  GETAUTHINFO -- get the real host name associated with a file descriptor
3065 **
3066 **	Parameters:
3067 **		fd -- the descriptor
3068 **		may_be_forged -- an outage that is set to TRUE if the
3069 **			forward lookup of RealHostName does not match
3070 **			RealHostAddr; set to FALSE if they do match.
3071 **
3072 **	Returns:
3073 **		The host name associated with this descriptor, if it can
3074 **			be determined.
3075 **		NULL otherwise.
3076 **
3077 **	Side Effects:
3078 **		none
3079 */
3080 
3081 char *
3082 getauthinfo(fd, may_be_forged)
3083 	int fd;
3084 	bool *may_be_forged;
3085 {
3086 	*may_be_forged = FALSE;
3087 	return NULL;
3088 }
3089 /*
3090 **  HOST_MAP_LOOKUP -- turn a hostname into canonical form
3091 **
3092 **	Parameters:
3093 **		map -- a pointer to the database map.
3094 **		name -- a buffer containing a hostname.
3095 **		avp -- a pointer to a (cf file defined) argument vector.
3096 **		statp -- an exit status (out parameter).
3097 **
3098 **	Returns:
3099 **		mapped host name
3100 **		FALSE otherwise.
3101 **
3102 **	Side Effects:
3103 **		Looks up the host specified in name.  If it is not
3104 **		the canonical name for that host, replace it with
3105 **		the canonical name.  If the name is unknown, or it
3106 **		is already the canonical name, leave it unchanged.
3107 */
3108 
3109 /*ARGSUSED*/
3110 char *
3111 host_map_lookup(map, name, avp, statp)
3112 	MAP *map;
3113 	char *name;
3114 	char **avp;
3115 	char *statp;
3116 {
3117 	register struct hostent *hp = NULL;
3118 	char *cp;
3119 
3120 	hp = sm_gethostbyname(name, InetMode);
3121 	if (hp == NULL && InetMode != AF_INET)
3122 		hp = sm_gethostbyname(name, AF_INET);
3123 	if (hp == NULL)
3124 	{
3125 # if NAMED_BIND
3126 		if (tTd(9, 1))
3127 			dprintf("FAIL (%d)\n", h_errno);
3128 		switch (h_errno)
3129 		{
3130 		  case TRY_AGAIN:
3131 			if (UseNameServer)
3132 			{
3133 				CurEnv->e_status = "4.4.3";
3134 				message("851 %s: Name server timeout",
3135 					shortenstring(name, 33));
3136 			}
3137 			*statp = EX_TEMPFAIL;
3138 			break;
3139 
3140 		  case HOST_NOT_FOUND:
3141 		  case NO_DATA:
3142 			*statp = EX_NOHOST;
3143 			break;
3144 
3145 		  case NO_RECOVERY:
3146 			*statp = EX_SOFTWARE;
3147 			break;
3148 
3149 		  default:
3150 			*statp = EX_UNAVAILABLE;
3151 			break;
3152 		}
3153 #else /* NAMED_BIND */
3154 		*statp = EX_NOHOST;
3155 #endif /* NAMED_BIND */
3156 		return NULL;
3157 	}
3158 	if (bitset(MF_MATCHONLY, map->map_mflags))
3159 		cp = map_rewrite(map, name, strlen(name), NULL);
3160 	else
3161 		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
3162 	return cp;
3163 }
3164 
3165 #endif /* DAEMON */
3166 /*
3167 **  HOST_MAP_INIT -- initialize host class structures
3168 */
3169 
3170 bool
3171 host_map_init(map, args)
3172 	MAP *map;
3173 	char *args;
3174 {
3175 	register char *p = args;
3176 
3177 	for (;;)
3178 	{
3179 		while (isascii(*p) && isspace(*p))
3180 			p++;
3181 		if (*p != '-')
3182 			break;
3183 		switch (*++p)
3184 		{
3185 		  case 'a':
3186 			map->map_app = ++p;
3187 			break;
3188 
3189 		  case 'T':
3190 			map->map_tapp = ++p;
3191 			break;
3192 
3193 		  case 'm':
3194 			map->map_mflags |= MF_MATCHONLY;
3195 			break;
3196 
3197 		  case 't':
3198 			map->map_mflags |= MF_NODEFER;
3199 			break;
3200 
3201 		  case 'S':	/* only for consistency */
3202 			map->map_spacesub = *++p;
3203 			break;
3204 
3205 		  case 'D':
3206 			map->map_mflags |= MF_DEFER;
3207 			break;
3208 		}
3209 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
3210 			p++;
3211 		if (*p != '\0')
3212 			*p++ = '\0';
3213 	}
3214 	if (map->map_app != NULL)
3215 		map->map_app = newstr(map->map_app);
3216 	if (map->map_tapp != NULL)
3217 		map->map_tapp = newstr(map->map_tapp);
3218 	return TRUE;
3219 }
3220 
3221 #if NETINET6
3222 /*
3223 **  ANYNET_NTOP -- convert an IPv6 network address to printable form.
3224 **
3225 **	Parameters:
3226 **		s6a -- a pointer to an in6_addr structure.
3227 **		dst -- buffer to store result in
3228 **		dst_len -- size of dst buffer
3229 **
3230 **	Returns:
3231 **		A printable version of that structure.
3232 */
3233 char *
3234 anynet_ntop(s6a, dst, dst_len)
3235 	struct in6_addr *s6a;
3236 	char *dst;
3237 	size_t dst_len;
3238 {
3239 	register char *ap;
3240 
3241 	if (IN6_IS_ADDR_V4MAPPED(s6a))
3242 		ap = (char *) inet_ntop(AF_INET,
3243 					&s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
3244 					dst, dst_len);
3245 	else
3246 		ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
3247 	return ap;
3248 }
3249 #endif /* NETINET6 */
3250 /*
3251 **  ANYNET_NTOA -- convert a network address to printable form.
3252 **
3253 **	Parameters:
3254 **		sap -- a pointer to a sockaddr structure.
3255 **
3256 **	Returns:
3257 **		A printable version of that sockaddr.
3258 */
3259 
3260 #ifdef USE_SOCK_STREAM
3261 
3262 # if NETLINK
3263 #  include <net/if_dl.h>
3264 # endif /* NETLINK */
3265 
3266 char *
3267 anynet_ntoa(sap)
3268 	register SOCKADDR *sap;
3269 {
3270 	register char *bp;
3271 	register char *ap;
3272 	int l;
3273 	static char buf[100];
3274 
3275 	/* check for null/zero family */
3276 	if (sap == NULL)
3277 		return "NULLADDR";
3278 	if (sap->sa.sa_family == 0)
3279 		return "0";
3280 
3281 	switch (sap->sa.sa_family)
3282 	{
3283 # if NETUNIX
3284 	  case AF_UNIX:
3285 		if (sap->sunix.sun_path[0] != '\0')
3286 			snprintf(buf, sizeof buf, "[UNIX: %.64s]",
3287 				sap->sunix.sun_path);
3288 		else
3289 			snprintf(buf, sizeof buf, "[UNIX: localhost]");
3290 		return buf;
3291 # endif /* NETUNIX */
3292 
3293 # if NETINET
3294 	  case AF_INET:
3295 		return (char *) inet_ntoa(sap->sin.sin_addr);
3296 # endif /* NETINET */
3297 
3298 # if NETINET6
3299 	  case AF_INET6:
3300 		ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf);
3301 		if (ap != NULL)
3302 			return ap;
3303 		break;
3304 # endif /* NETINET6 */
3305 
3306 # if NETLINK
3307 	  case AF_LINK:
3308 		snprintf(buf, sizeof buf, "[LINK: %s]",
3309 			link_ntoa((struct sockaddr_dl *) &sap->sa));
3310 		return buf;
3311 # endif /* NETLINK */
3312 	  default:
3313 		/* this case is needed when nothing is #defined */
3314 		/* in order to keep the switch syntactically correct */
3315 		break;
3316 	}
3317 
3318 	/* unknown family -- just dump bytes */
3319 	(void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
3320 	bp = &buf[strlen(buf)];
3321 	ap = sap->sa.sa_data;
3322 	for (l = sizeof sap->sa.sa_data; --l >= 0; )
3323 	{
3324 		(void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
3325 		bp += 3;
3326 	}
3327 	*--bp = '\0';
3328 	return buf;
3329 }
3330 /*
3331 **  HOSTNAMEBYANYADDR -- return name of host based on address
3332 **
3333 **	Parameters:
3334 **		sap -- SOCKADDR pointer
3335 **
3336 **	Returns:
3337 **		text representation of host name.
3338 **
3339 **	Side Effects:
3340 **		none.
3341 */
3342 
3343 char *
3344 hostnamebyanyaddr(sap)
3345 	register SOCKADDR *sap;
3346 {
3347 	register struct hostent *hp;
3348 # if NAMED_BIND
3349 	int saveretry;
3350 # endif /* NAMED_BIND */
3351 # if NETINET6
3352 	struct in6_addr in6_addr;
3353 # endif /* NETINET6 */
3354 
3355 # if NAMED_BIND
3356 	/* shorten name server timeout to avoid higher level timeouts */
3357 	saveretry = _res.retry;
3358 	if (_res.retry * _res.retrans > 20)
3359 		_res.retry = 20 / _res.retrans;
3360 # endif /* NAMED_BIND */
3361 
3362 	switch (sap->sa.sa_family)
3363 	{
3364 # if NETINET
3365 	  case AF_INET:
3366 		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
3367 			INADDRSZ,
3368 			AF_INET);
3369 		break;
3370 # endif /* NETINET */
3371 
3372 # if NETINET6
3373 	  case AF_INET6:
3374 		hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
3375 				      IN6ADDRSZ,
3376 				      AF_INET6);
3377 		break;
3378 # endif /* NETINET6 */
3379 
3380 # if NETISO
3381 	  case AF_ISO:
3382 		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
3383 			sizeof sap->siso.siso_addr,
3384 			AF_ISO);
3385 		break;
3386 # endif /* NETISO */
3387 
3388 # if NETUNIX
3389 	  case AF_UNIX:
3390 		hp = NULL;
3391 		break;
3392 # endif /* NETUNIX */
3393 
3394 	  default:
3395 		hp = sm_gethostbyaddr(sap->sa.sa_data,
3396 			   sizeof sap->sa.sa_data,
3397 			   sap->sa.sa_family);
3398 		break;
3399 	}
3400 
3401 # if NAMED_BIND
3402 	_res.retry = saveretry;
3403 # endif /* NAMED_BIND */
3404 
3405 # if NETINET || NETINET6
3406 	if (hp != NULL && hp->h_name[0] != '['
3407 #  if NETINET6
3408 	    && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1
3409 #  endif /* NETINET6 */
3410 #  if NETINET
3411 	    && inet_addr(hp->h_name) == INADDR_NONE
3412 #  endif /* NETINET */
3413 	    )
3414 		return denlstring((char *) hp->h_name, TRUE, TRUE);
3415 # endif /* NETINET || NETINET6 */
3416 # if NETUNIX
3417 	if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
3418 		return "localhost";
3419 # endif /* NETUNIX */
3420 	{
3421 		static char buf[203];
3422 
3423 		(void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
3424 		return buf;
3425 	}
3426 }
3427 #endif /* USE_SOCK_STREAM */
3428