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