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