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