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