daemon.c revision 38032
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#include <errno.h>
14#include "sendmail.h"
15
16#ifndef lint
17#ifdef DAEMON
18static char sccsid[] = "@(#)daemon.c	8.220 (Berkeley) 6/24/98 (with daemon mode)";
19#else
20static char sccsid[] = "@(#)daemon.c	8.220 (Berkeley) 6/24/98 (without daemon mode)";
21#endif
22#endif /* not lint */
23
24#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
25# define USE_SOCK_STREAM	1
26#endif
27
28#if DAEMON || defined(USE_SOCK_STREAM)
29# include <arpa/inet.h>
30# if NAMED_BIND
31#  include <resolv.h>
32#  ifndef NO_DATA
33#   define NO_DATA	NO_ADDRESS
34#  endif
35# endif
36#endif
37
38#if DAEMON
39
40# include <sys/time.h>
41
42# if IP_SRCROUTE
43#  include <netinet/in_systm.h>
44#  include <netinet/ip.h>
45#  include <netinet/ip_var.h>
46# endif
47
48/*
49**  DAEMON.C -- routines to use when running as a daemon.
50**
51**	This entire file is highly dependent on the 4.2 BSD
52**	interprocess communication primitives.  No attempt has
53**	been made to make this file portable to Version 7,
54**	Version 6, MPX files, etc.  If you should try such a
55**	thing yourself, I recommend chucking the entire file
56**	and starting from scratch.  Basic semantics are:
57**
58**	getrequests(e)
59**		Opens a port and initiates a connection.
60**		Returns in a child.  Must set InChannel and
61**		OutChannel appropriately.
62**	clrdaemon()
63**		Close any open files associated with getting
64**		the connection; this is used when running the queue,
65**		etc., to avoid having extra file descriptors during
66**		the queue run and to avoid confusing the network
67**		code (if it cares).
68**	makeconnection(host, port, outfile, infile, e)
69**		Make a connection to the named host on the given
70**		port.  Set *outfile and *infile to the files
71**		appropriate for communication.  Returns zero on
72**		success, else an exit status describing the
73**		error.
74**	host_map_lookup(map, hbuf, avp, pstat)
75**		Convert the entry in hbuf into a canonical form.
76*/
77/*
78**  GETREQUESTS -- open mail IPC port and get requests.
79**
80**	Parameters:
81**		e -- the current envelope.
82**
83**	Returns:
84**		none.
85**
86**	Side Effects:
87**		Waits until some interesting activity occurs.  When
88**		it does, a child is created to process it, and the
89**		parent waits for completion.  Return from this
90**		routine is always in the child.  The file pointers
91**		"InChannel" and "OutChannel" should be set to point
92**		to the communication channel.
93*/
94
95int		DaemonSocket	= -1;		/* fd describing socket */
96SOCKADDR	DaemonAddr;			/* socket for incoming */
97int		ListenQueueSize = 10;		/* size of listen queue */
98int		TcpRcvBufferSize = 0;		/* size of TCP receive buffer */
99int		TcpSndBufferSize = 0;		/* size of TCP send buffer */
100
101void
102getrequests(e)
103	ENVELOPE *e;
104{
105	int t;
106	bool refusingconnections = TRUE;
107	FILE *pidf;
108	int socksize;
109	u_short port;
110#if XDEBUG
111	bool j_has_dot;
112#endif
113	extern void reapchild __P((int));
114	extern int opendaemonsocket __P((bool));
115
116	/*
117	**  Set up the address for the mailer.
118	*/
119
120	switch (DaemonAddr.sa.sa_family)
121	{
122	  case AF_UNSPEC:
123		DaemonAddr.sa.sa_family = AF_INET;
124		/* fall through ... */
125
126	  case AF_INET:
127		if (DaemonAddr.sin.sin_addr.s_addr == 0)
128			DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
129		port = DaemonAddr.sin.sin_port;
130		break;
131
132	  default:
133		/* unknown protocol */
134		port = 0;
135		break;
136	}
137	if (port == 0)
138	{
139		register struct servent *sp;
140
141		sp = getservbyname("smtp", "tcp");
142		if (sp == NULL)
143		{
144			syserr("554 service \"smtp\" unknown");
145			port = htons(25);
146		}
147		else
148			port = sp->s_port;
149	}
150
151	switch (DaemonAddr.sa.sa_family)
152	{
153	  case AF_INET:
154		DaemonAddr.sin.sin_port = port;
155		break;
156
157	  default:
158		/* unknown protocol */
159		break;
160	}
161
162	/*
163	**  Try to actually open the connection.
164	*/
165
166	if (tTd(15, 1))
167		printf("getrequests: port 0x%x\n", port);
168
169	/* get a socket for the SMTP connection */
170	socksize = opendaemonsocket(TRUE);
171
172	(void) setsignal(SIGCHLD, reapchild);
173
174	/* write the pid to the log file for posterity */
175	pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644,
176			 SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT);
177	if (pidf == NULL)
178	{
179		sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile);
180	}
181	else
182	{
183		extern char *CommandLineArgs;
184
185		/* write the process id on line 1 */
186		fprintf(pidf, "%ld\n", (long) getpid());
187
188		/* line 2 contains all command line flags */
189		fprintf(pidf, "%s\n", CommandLineArgs);
190
191		/* flush and close */
192		fclose(pidf);
193	}
194
195#if XDEBUG
196	{
197		char jbuf[MAXHOSTNAMELEN];
198
199		expand("\201j", jbuf, sizeof jbuf, e);
200		j_has_dot = strchr(jbuf, '.') != NULL;
201	}
202#endif
203
204	if (tTd(15, 1))
205		printf("getrequests: %d\n", DaemonSocket);
206
207	for (;;)
208	{
209		register pid_t pid;
210		auto SOCKADDR_LEN_T lotherend;
211		int savederrno;
212		int pipefd[2];
213		extern bool refuseconnections __P((int));
214
215		/* see if we are rejecting connections */
216		(void) blocksignal(SIGALRM);
217		if (refuseconnections(ntohs(port)))
218		{
219			if (DaemonSocket >= 0)
220			{
221				/* close socket so peer will fail quickly */
222				(void) close(DaemonSocket);
223				DaemonSocket = -1;
224			}
225			refusingconnections = TRUE;
226			sleep(15);
227			continue;
228		}
229
230		/* arrange to (re)open the socket if necessary */
231		if (refusingconnections)
232		{
233			(void) opendaemonsocket(FALSE);
234			refusingconnections = FALSE;
235		}
236
237#if XDEBUG
238		/* check for disaster */
239		{
240			char jbuf[MAXHOSTNAMELEN];
241			extern void dumpstate __P((char *));
242
243			expand("\201j", jbuf, sizeof jbuf, e);
244			if (!wordinclass(jbuf, 'w'))
245			{
246				dumpstate("daemon lost $j");
247				sm_syslog(LOG_ALERT, NOQID,
248					"daemon process doesn't have $j in $=w; see syslog");
249				abort();
250			}
251			else if (j_has_dot && strchr(jbuf, '.') == NULL)
252			{
253				dumpstate("daemon $j lost dot");
254				sm_syslog(LOG_ALERT, NOQID,
255					"daemon process $j lost dot; see syslog");
256				abort();
257			}
258		}
259#endif
260
261		/* wait for a connection */
262		setproctitle("accepting connections on port %d",
263			     ntohs(port));
264#if 0
265		/*
266		**  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
267		**  fix the SVr4 problem.  But it seems to have gone away,
268		**  so is it worth doing this?
269		*/
270
271		if (SetNonBlocking(DaemonSocket, FALSE) < 0)
272			log an error here;
273#endif
274		(void) releasesignal(SIGALRM);
275		for (;;)
276		{
277			fd_set readfds;
278			struct timeval timeout;
279
280			FD_ZERO(&readfds);
281			FD_SET(DaemonSocket, &readfds);
282			timeout.tv_sec = 60;
283			timeout.tv_usec = 0;
284
285			t = select(DaemonSocket + 1, FDSET_CAST &readfds,
286				   NULL, NULL, &timeout);
287			if (DoQueueRun)
288				(void) runqueue(TRUE, FALSE);
289			if (t <= 0 || !FD_ISSET(DaemonSocket, &readfds))
290				continue;
291
292			errno = 0;
293			lotherend = socksize;
294			t = accept(DaemonSocket,
295			    (struct sockaddr *)&RealHostAddr, &lotherend);
296			if (t >= 0 || errno != EINTR)
297				break;
298		}
299		savederrno = errno;
300		(void) blocksignal(SIGALRM);
301		if (t < 0)
302		{
303			errno = savederrno;
304			syserr("getrequests: accept");
305
306			/* arrange to re-open the socket next time around */
307			(void) close(DaemonSocket);
308			DaemonSocket = -1;
309			refusingconnections = TRUE;
310			sleep(5);
311			continue;
312		}
313
314		/*
315		**  Create a subprocess to process the mail.
316		*/
317
318		if (tTd(15, 2))
319			printf("getrequests: forking (fd = %d)\n", t);
320
321		/*
322		**  Create a pipe to keep the child from writing to the
323		**  socket until after the parent has closed it.  Otherwise
324		**  the parent may hang if the child has closed it first.
325		*/
326
327		if (pipe(pipefd) < 0)
328			pipefd[0] = pipefd[1] = -1;
329
330		blocksignal(SIGCHLD);
331		pid = fork();
332		if (pid < 0)
333		{
334			syserr("daemon: cannot fork");
335			if (pipefd[0] != -1)
336			{
337				(void) close(pipefd[0]);
338				(void) close(pipefd[1]);
339			}
340			(void) releasesignal(SIGCHLD);
341			sleep(10);
342			(void) close(t);
343			continue;
344		}
345
346		if (pid == 0)
347		{
348			char *p;
349			extern SIGFUNC_DECL intsig __P((int));
350			FILE *inchannel, *outchannel;
351
352			/*
353			**  CHILD -- return to caller.
354			**	Collect verified idea of sending host.
355			**	Verify calling user id if possible here.
356			*/
357
358			(void) releasesignal(SIGALRM);
359			(void) releasesignal(SIGCHLD);
360			(void) setsignal(SIGCHLD, SIG_DFL);
361			(void) setsignal(SIGHUP, intsig);
362			(void) close(DaemonSocket);
363			proc_list_clear();
364
365			/* don't schedule queue runs if we are told to ETRN */
366			QueueIntvl = 0;
367
368			setproctitle("startup with %s",
369				anynet_ntoa(&RealHostAddr));
370
371			if (pipefd[0] != -1)
372			{
373				auto char c;
374
375				/*
376				**  Wait for the parent to close the write end
377				**  of the pipe, which we will see as an EOF.
378				**  This guarantees that we won't write to the
379				**  socket until after the parent has closed
380				**  the pipe.
381				*/
382
383				/* close the write end of the pipe */
384				(void) close(pipefd[1]);
385
386				/* we shouldn't be interrupted, but ... */
387				while (read(pipefd[0], &c, 1) < 0 &&
388				       errno == EINTR)
389					continue;
390				(void) close(pipefd[0]);
391			}
392
393			/* determine host name */
394			p = hostnamebyanyaddr(&RealHostAddr);
395			if (strlen(p) > (SIZE_T) MAXNAME)
396				p[MAXNAME] = '\0';
397			RealHostName = newstr(p);
398			setproctitle("startup with %s", p);
399
400			if ((inchannel = fdopen(t, "r")) == NULL ||
401			    (t = dup(t)) < 0 ||
402			    (outchannel = fdopen(t, "w")) == NULL)
403			{
404				syserr("cannot open SMTP server channel, fd=%d", t);
405				exit(EX_OK);
406			}
407
408			InChannel = inchannel;
409			OutChannel = outchannel;
410			DisConnected = FALSE;
411
412			/* open maps for check_relay ruleset */
413			initmaps(FALSE, e);
414
415#ifdef XLA
416			if (!xla_host_ok(RealHostName))
417			{
418				message("421 Too many SMTP sessions for this host");
419				exit(EX_OK);
420			}
421#endif
422
423			break;
424		}
425
426		/* parent -- keep track of children */
427		proc_list_add(pid);
428		(void) releasesignal(SIGCHLD);
429
430		/* close the read end of the synchronization pipe */
431		if (pipefd[0] != -1)
432			(void) close(pipefd[0]);
433
434		/* close the port so that others will hang (for a while) */
435		(void) close(t);
436
437		/* release the child by closing the read end of the sync pipe */
438		if (pipefd[1] != -1)
439			(void) close(pipefd[1]);
440	}
441	if (tTd(15, 2))
442		printf("getreq: returning\n");
443	return;
444}
445/*
446**  OPENDAEMONSOCKET -- open the SMTP socket
447**
448**	Deals with setting all appropriate options.  DaemonAddr must
449**	be set up in advance.
450**
451**	Parameters:
452**		firsttime -- set if this is the initial open.
453**
454**	Returns:
455**		Size in bytes of the daemon socket addr.
456**
457**	Side Effects:
458**		Leaves DaemonSocket set to the open socket.
459**		Exits if the socket cannot be created.
460*/
461
462#define MAXOPENTRIES	10	/* maximum number of tries to open connection */
463
464int
465opendaemonsocket(firsttime)
466	bool firsttime;
467{
468	int on = 1;
469	int socksize = 0;
470	int ntries = 0;
471	int saveerrno;
472
473	if (tTd(15, 2))
474		printf("opendaemonsocket()\n");
475
476	do
477	{
478		if (ntries > 0)
479			sleep(5);
480		if (firsttime || DaemonSocket < 0)
481		{
482			DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
483			if (DaemonSocket < 0)
484			{
485				saveerrno = errno;
486				syserr("opendaemonsocket: can't create server SMTP socket");
487			  severe:
488				if (LogLevel > 0)
489					sm_syslog(LOG_ALERT, NOQID,
490						"problem creating SMTP socket");
491				DaemonSocket = -1;
492				continue;
493			}
494
495			/* turn on network debugging? */
496			if (tTd(15, 101))
497				(void) setsockopt(DaemonSocket, SOL_SOCKET,
498						  SO_DEBUG, (char *)&on,
499						  sizeof on);
500
501			(void) setsockopt(DaemonSocket, SOL_SOCKET,
502					  SO_REUSEADDR, (char *)&on, sizeof on);
503			(void) setsockopt(DaemonSocket, SOL_SOCKET,
504					  SO_KEEPALIVE, (char *)&on, sizeof on);
505
506#ifdef SO_RCVBUF
507			if (TcpRcvBufferSize > 0)
508			{
509				if (setsockopt(DaemonSocket, SOL_SOCKET,
510					       SO_RCVBUF,
511					       (char *) &TcpRcvBufferSize,
512					       sizeof(TcpRcvBufferSize)) < 0)
513					syserr("opendaemonsocket: setsockopt(SO_RCVBUF)");
514			}
515#endif
516
517			switch (DaemonAddr.sa.sa_family)
518			{
519# if NETINET
520			  case AF_INET:
521				socksize = sizeof DaemonAddr.sin;
522				break;
523# endif
524
525# if NETISO
526			  case AF_ISO:
527				socksize = sizeof DaemonAddr.siso;
528				break;
529# endif
530
531			  default:
532				socksize = sizeof DaemonAddr;
533				break;
534			}
535
536			if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
537			{
538				/* probably another daemon already */
539				saveerrno = errno;
540				syserr("opendaemonsocket: cannot bind");
541				(void) close(DaemonSocket);
542				goto severe;
543			}
544		}
545		if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
546		{
547			saveerrno = errno;
548			syserr("opendaemonsocket: cannot listen");
549			(void) close(DaemonSocket);
550			goto severe;
551		}
552		return socksize;
553	} while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
554	syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
555	finis();
556	return -1;  /* avoid compiler warning on IRIX */
557}
558/*
559**  CLRDAEMON -- reset the daemon connection
560**
561**	Parameters:
562**		none.
563**
564**	Returns:
565**		none.
566**
567**	Side Effects:
568**		releases any resources used by the passive daemon.
569*/
570
571void
572clrdaemon()
573{
574	if (DaemonSocket >= 0)
575		(void) close(DaemonSocket);
576	DaemonSocket = -1;
577}
578/*
579**  SETDAEMONOPTIONS -- set options for running the daemon
580**
581**	Parameters:
582**		p -- the options line.
583**
584**	Returns:
585**		none.
586*/
587
588void
589setdaemonoptions(p)
590	register char *p;
591{
592	if (DaemonAddr.sa.sa_family == AF_UNSPEC)
593		DaemonAddr.sa.sa_family = AF_INET;
594
595	while (p != NULL)
596	{
597		register char *f;
598		register char *v;
599
600		while (isascii(*p) && isspace(*p))
601			p++;
602		if (*p == '\0')
603			break;
604		f = p;
605		p = strchr(p, ',');
606		if (p != NULL)
607			*p++ = '\0';
608		v = strchr(f, '=');
609		if (v == NULL)
610			continue;
611		while (isascii(*++v) && isspace(*v))
612			continue;
613		if (isascii(*f) && islower(*f))
614			*f = toupper(*f);
615
616		switch (*f)
617		{
618		  case 'F':		/* address family */
619			if (isascii(*v) && isdigit(*v))
620				DaemonAddr.sa.sa_family = atoi(v);
621#if NETINET
622			else if (strcasecmp(v, "inet") == 0)
623				DaemonAddr.sa.sa_family = AF_INET;
624#endif
625#if NETISO
626			else if (strcasecmp(v, "iso") == 0)
627				DaemonAddr.sa.sa_family = AF_ISO;
628#endif
629#if NETNS
630			else if (strcasecmp(v, "ns") == 0)
631				DaemonAddr.sa.sa_family = AF_NS;
632#endif
633#if NETX25
634			else if (strcasecmp(v, "x.25") == 0)
635				DaemonAddr.sa.sa_family = AF_CCITT;
636#endif
637			else
638				syserr("554 Unknown address family %s in Family=option", v);
639			break;
640
641		  case 'A':		/* address */
642			switch (DaemonAddr.sa.sa_family)
643			{
644#if NETINET
645			  case AF_INET:
646				if (isascii(*v) && isdigit(*v))
647					DaemonAddr.sin.sin_addr.s_addr = inet_addr(v);
648				else
649				{
650					register struct hostent *hp;
651
652					hp = sm_gethostbyname(v);
653					if (hp == NULL)
654						syserr("554 host \"%s\" unknown", v);
655					else
656						bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ);
657				}
658				break;
659#endif
660
661			  default:
662				syserr("554 Address= option unsupported for family %d",
663					DaemonAddr.sa.sa_family);
664				break;
665			}
666			break;
667
668		  case 'P':		/* port */
669			switch (DaemonAddr.sa.sa_family)
670			{
671#if NETISO
672				short port;
673#endif
674
675#if NETINET
676			  case AF_INET:
677				if (isascii(*v) && isdigit(*v))
678					DaemonAddr.sin.sin_port = htons(atoi(v));
679				else
680				{
681					register struct servent *sp;
682
683					sp = getservbyname(v, "tcp");
684					if (sp == NULL)
685						syserr("554 service \"%s\" unknown", v);
686					else
687						DaemonAddr.sin.sin_port = sp->s_port;
688				}
689				break;
690#endif
691
692#if NETISO
693			  case AF_ISO:
694				/* assume two byte transport selector */
695				if (isascii(*v) && isdigit(*v))
696					port = htons(atoi(v));
697				else
698				{
699					register struct servent *sp;
700
701					sp = getservbyname(v, "tcp");
702					if (sp == NULL)
703						syserr("554 service \"%s\" unknown", v);
704					else
705						port = sp->s_port;
706				}
707				bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
708				break;
709#endif
710
711			  default:
712				syserr("554 Port= option unsupported for family %d",
713					DaemonAddr.sa.sa_family);
714				break;
715			}
716			break;
717
718		  case 'L':		/* listen queue size */
719			ListenQueueSize = atoi(v);
720			break;
721
722		  case 'S':		/* send buffer size */
723			TcpSndBufferSize = atoi(v);
724			break;
725
726		  case 'R':		/* receive buffer size */
727			TcpRcvBufferSize = atoi(v);
728			break;
729
730		  default:
731			syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
732		}
733	}
734}
735/*
736**  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
737**
738**	Parameters:
739**		host -- the name of the host.
740**		port -- the port number to connect to.
741**		mci -- a pointer to the mail connection information
742**			structure to be filled in.
743**		e -- the current envelope.
744**
745**	Returns:
746**		An exit code telling whether the connection could be
747**			made and if not why not.
748**
749**	Side Effects:
750**		none.
751*/
752
753static jmp_buf	CtxConnectTimeout;
754
755static void
756connecttimeout()
757{
758	errno = ETIMEDOUT;
759	longjmp(CtxConnectTimeout, 1);
760}
761
762SOCKADDR	CurHostAddr;		/* address of current host */
763
764int
765makeconnection(host, port, mci, e)
766	char *host;
767	u_short port;
768	register MCI *mci;
769	ENVELOPE *e;
770{
771	register volatile int addrno = 0;
772	register volatile int s;
773	register struct hostent *volatile hp = (struct hostent *)NULL;
774	SOCKADDR addr;
775	int sav_errno;
776	volatile int addrlen;
777	volatile bool firstconnect;
778	EVENT *volatile ev = NULL;
779
780	/*
781	**  Set up the address for the mailer.
782	**	Accept "[a.b.c.d]" syntax for host name.
783	*/
784
785#if NAMED_BIND
786	h_errno = 0;
787#endif
788	errno = 0;
789	bzero(&CurHostAddr, sizeof CurHostAddr);
790	SmtpPhase = mci->mci_phase = "initial connection";
791	CurHostName = host;
792
793	if (host[0] == '[')
794	{
795#if NETINET
796		unsigned long hid = INADDR_NONE;
797#endif
798		register char *p = strchr(host, ']');
799
800		if (p != NULL)
801		{
802			*p = '\0';
803#if NETINET
804			hid = inet_addr(&host[1]);
805			if (hid == INADDR_NONE)
806#endif
807			{
808				/* try it as a host name (avoid MX lookup) */
809				hp = sm_gethostbyname(&host[1]);
810				if (hp == NULL && p[-1] == '.')
811				{
812#if NAMED_BIND
813					int oldopts = _res.options;
814
815					_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
816#endif
817					p[-1] = '\0';
818					hp = sm_gethostbyname(&host[1]);
819					p[-1] = '.';
820#if NAMED_BIND
821					_res.options = oldopts;
822#endif
823				}
824				*p = ']';
825				goto gothostent;
826			}
827			*p = ']';
828		}
829		if (p == NULL)
830		{
831			extern char MsgBuf[];
832
833			usrerr("553 Invalid numeric domain spec \"%s\"", host);
834			mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
835			return EX_NOHOST;
836		}
837#if NETINET
838		addr.sin.sin_family = AF_INET;		/*XXX*/
839		addr.sin.sin_addr.s_addr = hid;
840#endif
841	}
842	else
843	{
844		/* contortion to get around SGI cc complaints */
845		{
846			register char *p = &host[strlen(host) - 1];
847
848			hp = sm_gethostbyname(host);
849			if (hp == NULL && *p == '.')
850			{
851#if NAMED_BIND
852				int oldopts = _res.options;
853
854				_res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
855#endif
856				*p = '\0';
857				hp = sm_gethostbyname(host);
858				*p = '.';
859#if NAMED_BIND
860				_res.options = oldopts;
861#endif
862			}
863		}
864gothostent:
865		if (hp == NULL)
866		{
867#if NAMED_BIND
868			/* check for name server timeouts */
869			if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
870			    (errno == ECONNREFUSED && UseNameServer))
871			{
872				mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
873				return EX_TEMPFAIL;
874			}
875#endif
876			mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
877			return (EX_NOHOST);
878		}
879		addr.sa.sa_family = hp->h_addrtype;
880		switch (hp->h_addrtype)
881		{
882#if NETINET
883		  case AF_INET:
884			bcopy(hp->h_addr,
885				&addr.sin.sin_addr,
886				INADDRSZ);
887			break;
888#endif
889
890		  default:
891			if (hp->h_length > sizeof addr.sa.sa_data)
892			{
893				syserr("makeconnection: long sa_data: family %d len %d",
894					hp->h_addrtype, hp->h_length);
895				mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
896				return EX_NOHOST;
897			}
898			bcopy(hp->h_addr,
899				addr.sa.sa_data,
900				hp->h_length);
901			break;
902		}
903		addrno = 1;
904	}
905
906	/*
907	**  Determine the port number.
908	*/
909
910	if (port == 0)
911	{
912		register struct servent *sp = getservbyname("smtp", "tcp");
913
914		if (sp == NULL)
915		{
916			if (LogLevel > 2)
917				sm_syslog(LOG_ERR, NOQID,
918					"makeconnection: service \"smtp\" unknown");
919			port = htons(25);
920		}
921		else
922			port = sp->s_port;
923	}
924
925	switch (addr.sa.sa_family)
926	{
927#if NETINET
928	  case AF_INET:
929		addr.sin.sin_port = port;
930		addrlen = sizeof (struct sockaddr_in);
931		break;
932#endif
933
934#if NETISO
935	  case AF_ISO:
936		/* assume two byte transport selector */
937		bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
938		addrlen = sizeof (struct sockaddr_iso);
939		break;
940#endif
941
942	  default:
943		syserr("Can't connect to address family %d", addr.sa.sa_family);
944		mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
945		return (EX_NOHOST);
946	}
947
948	/*
949	**  Try to actually open the connection.
950	*/
951
952#ifdef XLA
953	/* if too many connections, don't bother trying */
954	if (!xla_noqueue_ok(host))
955		return EX_TEMPFAIL;
956#endif
957
958	firstconnect = TRUE;
959	for (;;)
960	{
961		if (tTd(16, 1))
962			printf("makeconnection (%s [%s])\n",
963				host, anynet_ntoa(&addr));
964
965		/* save for logging */
966		CurHostAddr = addr;
967
968		if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
969		{
970			int rport = IPPORT_RESERVED - 1;
971
972			s = rresvport(&rport);
973		}
974		else
975		{
976			s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
977		}
978		if (s < 0)
979		{
980			sav_errno = errno;
981			syserr("makeconnection: cannot create socket");
982#ifdef XLA
983			xla_host_end(host);
984#endif
985			mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
986			return EX_TEMPFAIL;
987		}
988
989#ifdef SO_SNDBUF
990		if (TcpSndBufferSize > 0)
991		{
992			if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
993				       (char *) &TcpSndBufferSize,
994				       sizeof(TcpSndBufferSize)) < 0)
995				syserr("makeconnection: setsockopt(SO_SNDBUF)");
996		}
997#endif
998
999		if (tTd(16, 1))
1000			printf("makeconnection: fd=%d\n", s);
1001
1002		/* turn on network debugging? */
1003		if (tTd(16, 101))
1004		{
1005			int on = 1;
1006			(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
1007					  (char *)&on, sizeof on);
1008		}
1009		if (e->e_xfp != NULL)
1010			(void) fflush(e->e_xfp);		/* for debugging */
1011		errno = 0;					/* for debugging */
1012
1013		/*
1014		**  Linux seems to hang in connect for 90 minutes (!!!).
1015		**  Time out the connect to avoid this problem.
1016		*/
1017
1018		if (setjmp(CtxConnectTimeout) == 0)
1019		{
1020			int i;
1021
1022			if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
1023				ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
1024			else if (TimeOuts.to_connect != 0)
1025				ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
1026			else
1027				ev = NULL;
1028
1029#if _FFR_CONNECTONLYTO_OPTION
1030			/* for testing */
1031			if (ConnectOnlyTo != 0)
1032				addr.sin.sin_addr.s_addr = ConnectOnlyTo;
1033#endif
1034			i = connect(s, (struct sockaddr *) &addr, addrlen);
1035			sav_errno = errno;
1036			if (ev != NULL)
1037				clrevent(ev);
1038			if (i >= 0)
1039				break;
1040		}
1041		else
1042			sav_errno = errno;
1043
1044		/* if running demand-dialed connection, try again */
1045		if (DialDelay > 0 && firstconnect)
1046		{
1047			if (tTd(16, 1))
1048				printf("Connect failed (%s); trying again...\n",
1049					errstring(sav_errno));
1050			firstconnect = FALSE;
1051			sleep(DialDelay);
1052			continue;
1053		}
1054
1055		/* couldn't connect.... figure out why */
1056		(void) close(s);
1057
1058		if (LogLevel >= 14)
1059			sm_syslog(LOG_INFO, e->e_id,
1060				  "makeconnection (%s [%s]) failed: %s",
1061				  host, anynet_ntoa(&addr),
1062				  errstring(sav_errno));
1063
1064		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
1065		{
1066			if (tTd(16, 1))
1067				printf("Connect failed (%s); trying new address....\n",
1068					errstring(sav_errno));
1069			switch (addr.sa.sa_family)
1070			{
1071#if NETINET
1072			  case AF_INET:
1073				bcopy(hp->h_addr_list[addrno++],
1074				      &addr.sin.sin_addr,
1075				      INADDRSZ);
1076				break;
1077#endif
1078
1079			  default:
1080				bcopy(hp->h_addr_list[addrno++],
1081					addr.sa.sa_data,
1082					hp->h_length);
1083				break;
1084			}
1085			continue;
1086		}
1087
1088		/* couldn't open connection */
1089#ifdef XLA
1090		xla_host_end(host);
1091#endif
1092		mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
1093		return EX_TEMPFAIL;
1094	}
1095
1096	/* connection ok, put it into canonical form */
1097	if ((mci->mci_out = fdopen(s, "w")) == NULL ||
1098	    (s = dup(s)) < 0 ||
1099	    (mci->mci_in = fdopen(s, "r")) == NULL)
1100	{
1101		syserr("cannot open SMTP client channel, fd=%d", s);
1102		mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
1103		return EX_TEMPFAIL;
1104	}
1105
1106	mci_setstat(mci, EX_OK, NULL, NULL);
1107	return (EX_OK);
1108}
1109/*
1110**  MYHOSTNAME -- return the name of this host.
1111**
1112**	Parameters:
1113**		hostbuf -- a place to return the name of this host.
1114**		size -- the size of hostbuf.
1115**
1116**	Returns:
1117**		A list of aliases for this host.
1118**
1119**	Side Effects:
1120**		Adds numeric codes to $=w.
1121*/
1122
1123struct hostent *
1124myhostname(hostbuf, size)
1125	char hostbuf[];
1126	int size;
1127{
1128	register struct hostent *hp;
1129
1130	if (gethostname(hostbuf, size) < 0)
1131	{
1132		(void) strcpy(hostbuf, "localhost");
1133	}
1134	hp = sm_gethostbyname(hostbuf);
1135	if (hp == NULL)
1136		return NULL;
1137	if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
1138	{
1139		(void) strncpy(hostbuf, hp->h_name, size - 1);
1140		hostbuf[size - 1] = '\0';
1141	}
1142
1143	/*
1144	**  If there is still no dot in the name, try looking for a
1145	**  dotted alias.
1146	*/
1147
1148	if (strchr(hostbuf, '.') == NULL)
1149	{
1150		char **ha;
1151
1152		for (ha = hp->h_aliases; *ha != NULL; ha++)
1153		{
1154			if (strchr(*ha, '.') != NULL)
1155			{
1156				(void) strncpy(hostbuf, *ha, size - 1);
1157				hostbuf[size - 1] = '\0';
1158				break;
1159			}
1160		}
1161	}
1162
1163	/*
1164	**  If _still_ no dot, wait for a while and try again -- it is
1165	**  possible that some service is starting up.  This can result
1166	**  in excessive delays if the system is badly configured, but
1167	**  there really isn't a way around that, particularly given that
1168	**  the config file hasn't been read at this point.
1169	**  All in all, a bit of a mess.
1170	*/
1171
1172	if (strchr(hostbuf, '.') == NULL &&
1173	    !getcanonname(hostbuf, size, TRUE))
1174	{
1175		sm_syslog(LOG_CRIT, NOQID,
1176			"My unqualified host name (%s) unknown; sleeping for retry",
1177			hostbuf);
1178		message("My unqualified host name (%s) unknown; sleeping for retry",
1179			hostbuf);
1180		sleep(60);
1181		if (!getcanonname(hostbuf, size, TRUE))
1182		{
1183			sm_syslog(LOG_ALERT, NOQID,
1184				"unable to qualify my own domain name (%s) -- using short name",
1185				hostbuf);
1186			message("WARNING: unable to qualify my own domain name (%s) -- using short name",
1187				hostbuf);
1188		}
1189	}
1190	return (hp);
1191}
1192/*
1193**  ADDRCMP -- compare two host addresses
1194**
1195**	Parameters:
1196**		hp -- hostent structure for the first address
1197**		ha -- actual first address
1198**		sa -- second address
1199**
1200**	Returns:
1201**		0 -- if ha and sa match
1202**		else -- they don't match
1203*/
1204
1205int
1206addrcmp(hp, ha, sa)
1207	struct hostent *hp;
1208	char *ha;
1209	SOCKADDR *sa;
1210{
1211	switch (sa->sa.sa_family)
1212	{
1213	  case AF_INET:
1214		if (hp->h_addrtype == AF_INET)
1215			return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length);
1216		break;
1217
1218	}
1219	return -1;
1220}
1221/*
1222**  GETAUTHINFO -- get the real host name asociated with a file descriptor
1223**
1224**	Uses RFC1413 protocol to try to get info from the other end.
1225**
1226**	Parameters:
1227**		fd -- the descriptor
1228**		may_be_forged -- an outage that is set to TRUE if the
1229**			forward lookup of RealHostName does not match
1230**			RealHostAddr; set to FALSE if they do match.
1231**
1232**	Returns:
1233**		The user@host information associated with this descriptor.
1234*/
1235
1236static jmp_buf	CtxAuthTimeout;
1237
1238static void
1239authtimeout()
1240{
1241	longjmp(CtxAuthTimeout, 1);
1242}
1243
1244char *
1245getauthinfo(fd, may_be_forged)
1246	int fd;
1247	bool *may_be_forged;
1248{
1249	SOCKADDR_LEN_T falen;
1250	register char *volatile p = NULL;
1251	SOCKADDR la;
1252	SOCKADDR_LEN_T lalen;
1253	register struct servent *sp;
1254	volatile int s;
1255	int i = 0;
1256	EVENT *ev;
1257	int nleft;
1258	struct hostent *hp;
1259	char *ostype = NULL;
1260	char **ha;
1261	char ibuf[MAXNAME + 1];
1262	static char hbuf[MAXNAME * 2 + 11];
1263
1264	*may_be_forged = FALSE;
1265	falen = sizeof RealHostAddr;
1266	if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
1267	    falen <= 0 || RealHostAddr.sa.sa_family == 0)
1268	{
1269		if (i < 0 && errno != ENOTSOCK)
1270			return NULL;
1271		(void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
1272			RealUserName);
1273		if (tTd(9, 1))
1274			printf("getauthinfo: %s\n", hbuf);
1275		return hbuf;
1276	}
1277
1278	if (RealHostName == NULL)
1279	{
1280		/* translate that to a host name */
1281		RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
1282		if (strlen(RealHostName) > MAXNAME)
1283			RealHostName[MAXNAME - 1] = '\0';
1284	}
1285
1286	/* cross check RealHostName with forward DNS lookup */
1287	if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
1288	    RealHostName[0] == '[')
1289	{
1290		/*
1291		** address is not a socket or have an
1292		** IP address with no forward lookup
1293		*/
1294		*may_be_forged = FALSE;
1295	}
1296	else
1297	{
1298		/* try to match the reverse against the forward lookup */
1299		hp = sm_gethostbyname(RealHostName);
1300
1301		if (hp == NULL)
1302			*may_be_forged = TRUE;
1303		else
1304		{
1305			for (ha = hp->h_addr_list; *ha != NULL; ha++)
1306				if (addrcmp(hp, *ha, &RealHostAddr) == 0)
1307					break;
1308			*may_be_forged = *ha == NULL;
1309		}
1310	}
1311
1312	if (TimeOuts.to_ident == 0)
1313		goto noident;
1314
1315	lalen = sizeof la;
1316	if (RealHostAddr.sa.sa_family != AF_INET ||
1317	    getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
1318	    la.sa.sa_family != AF_INET)
1319	{
1320		/* no ident info */
1321		goto noident;
1322	}
1323
1324	/* create ident query */
1325	(void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
1326		ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
1327
1328	/* create local address */
1329	la.sin.sin_port = 0;
1330
1331	/* create foreign address */
1332	sp = getservbyname("auth", "tcp");
1333	if (sp != NULL)
1334		RealHostAddr.sin.sin_port = sp->s_port;
1335	else
1336		RealHostAddr.sin.sin_port = htons(113);
1337
1338	s = -1;
1339	if (setjmp(CtxAuthTimeout) != 0)
1340	{
1341		if (s >= 0)
1342			(void) close(s);
1343		goto noident;
1344	}
1345
1346	/* put a timeout around the whole thing */
1347	ev = setevent(TimeOuts.to_ident, authtimeout, 0);
1348
1349	/* connect to foreign IDENT server using same address as SMTP socket */
1350	s = socket(AF_INET, SOCK_STREAM, 0);
1351	if (s < 0)
1352	{
1353		clrevent(ev);
1354		goto noident;
1355	}
1356	if (bind(s, &la.sa, sizeof la.sin) < 0 ||
1357	    connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
1358	{
1359		goto closeident;
1360	}
1361
1362	if (tTd(9, 10))
1363		printf("getauthinfo: sent %s", ibuf);
1364
1365	/* send query */
1366	if (write(s, ibuf, strlen(ibuf)) < 0)
1367		goto closeident;
1368
1369	/* get result */
1370	p = &ibuf[0];
1371	nleft = sizeof ibuf - 1;
1372	while ((i = read(s, p, nleft)) > 0)
1373	{
1374		p += i;
1375		nleft -= i;
1376		*p = '\0';
1377		if (strchr(ibuf, '\n') != NULL)
1378			break;
1379	}
1380	(void) close(s);
1381	clrevent(ev);
1382	if (i < 0 || p == &ibuf[0])
1383		goto noident;
1384
1385	if (*--p == '\n' && *--p == '\r')
1386		p--;
1387	*++p = '\0';
1388
1389	if (tTd(9, 3))
1390		printf("getauthinfo:  got %s\n", ibuf);
1391
1392	/* parse result */
1393	p = strchr(ibuf, ':');
1394	if (p == NULL)
1395	{
1396		/* malformed response */
1397		goto noident;
1398	}
1399	while (isascii(*++p) && isspace(*p))
1400		continue;
1401	if (strncasecmp(p, "userid", 6) != 0)
1402	{
1403		/* presumably an error string */
1404		goto noident;
1405	}
1406	p += 6;
1407	while (isascii(*p) && isspace(*p))
1408		p++;
1409	if (*p++ != ':')
1410	{
1411		/* either useridxx or malformed response */
1412		goto noident;
1413	}
1414
1415	/* p now points to the OSTYPE field */
1416	while (isascii(*p) && isspace(*p))
1417		p++;
1418	ostype = p;
1419	p = strchr(p, ':');
1420	if (p == NULL)
1421	{
1422		/* malformed response */
1423		goto noident;
1424	}
1425	else
1426	{
1427		char *charset;
1428
1429		*p = '\0';
1430		charset = strchr(ostype, ',');
1431		if (charset != NULL)
1432			*charset = '\0';
1433	}
1434
1435	/* 1413 says don't do this -- but it's broken otherwise */
1436	while (isascii(*++p) && isspace(*p))
1437		continue;
1438
1439	/* p now points to the authenticated name -- copy carefully */
1440	if (strncasecmp(ostype, "other", 5) == 0 &&
1441	    (ostype[5] == ' ' || ostype[5] == '\0'))
1442	{
1443		snprintf(hbuf, sizeof hbuf, "IDENT:");
1444		cleanstrcpy(&hbuf[6], p, MAXNAME);
1445	}
1446	else
1447		cleanstrcpy(hbuf, p, MAXNAME);
1448	i = strlen(hbuf);
1449	snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
1450		 RealHostName == NULL ? "localhost" : RealHostName);
1451	goto postident;
1452
1453closeident:
1454	(void) close(s);
1455	clrevent(ev);
1456
1457noident:
1458	if (RealHostName == NULL)
1459	{
1460		if (tTd(9, 1))
1461			printf("getauthinfo: NULL\n");
1462		return NULL;
1463	}
1464	snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
1465
1466postident:
1467#if IP_SRCROUTE
1468# ifndef GET_IPOPT_DST
1469#  define GET_IPOPT_DST(dst)	(dst)
1470# endif
1471	/*
1472	**  Extract IP source routing information.
1473	**
1474	**	Format of output for a connection from site a through b
1475	**	through c to d:
1476	**		loose:      @site-c@site-b:site-a
1477	**		strict:	   !@site-c@site-b:site-a
1478	**
1479	**	o - pointer within ipopt_list structure.
1480	**	q - pointer within ls/ss rr route data
1481	**	p - pointer to hbuf
1482	*/
1483
1484	if (RealHostAddr.sa.sa_family == AF_INET)
1485	{
1486		SOCKOPT_LEN_T ipoptlen;
1487		int j;
1488		u_char *q;
1489		u_char *o;
1490		int l;
1491		struct in_addr addr;
1492		struct ipoption ipopt;
1493
1494		ipoptlen = sizeof ipopt;
1495		if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
1496			       (char *) &ipopt, &ipoptlen) < 0)
1497			goto noipsr;
1498		if (ipoptlen == 0)
1499			goto noipsr;
1500		o = (u_char *) ipopt.ipopt_list;
1501		while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
1502		{
1503			switch (*o)
1504			{
1505			  case IPOPT_EOL:
1506				o = NULL;
1507				break;
1508
1509			  case IPOPT_NOP:
1510				o++;
1511				break;
1512
1513			  case IPOPT_SSRR:
1514			  case IPOPT_LSRR:
1515				/*
1516				**  Source routing.
1517				**	o[0] is the option type (loose/strict).
1518				**	o[1] is the length of this option,
1519				**		including option type and
1520				**		length.
1521				**	o[2] is the pointer into the route
1522				**		data.
1523				**	o[3] begins the route data.
1524				*/
1525
1526				p = &hbuf[strlen(hbuf)];
1527				l = sizeof hbuf - (hbuf - p) - 6;
1528				snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
1529				    *o == IPOPT_SSRR ? "!" : "",
1530				    l > 240 ? 120 : l / 2,
1531				    inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst)));
1532				i = strlen(p);
1533				p += i;
1534				l -= strlen(p);
1535
1536				j = o[1] / sizeof(struct in_addr) - 1;
1537
1538				/* q skips length and router pointer to data */
1539				q = &o[3];
1540				for ( ; j >= 0; j--)
1541				{
1542					memcpy(&addr, q, sizeof(addr));
1543					snprintf(p, SPACELEFT(hbuf, p),
1544						"%c%.*s",
1545						j != 0 ? '@' : ':',
1546						l > 240 ? 120 :
1547						    j == 0 ? l : l / 2,
1548						inet_ntoa(addr));
1549					i = strlen(p);
1550					p += i;
1551					l -= i + 1;
1552					q += sizeof(struct in_addr);
1553				}
1554				o += o[1];
1555				break;
1556
1557			  default:
1558				/* Skip over option */
1559				o += o[1];
1560				break;
1561			}
1562		}
1563		snprintf(p, SPACELEFT(hbuf, p), "]");
1564		goto postipsr;
1565	}
1566
1567noipsr:
1568#endif
1569	if (RealHostName != NULL && RealHostName[0] != '[')
1570	{
1571		p = &hbuf[strlen(hbuf)];
1572		(void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
1573			anynet_ntoa(&RealHostAddr));
1574	}
1575	if (*may_be_forged)
1576	{
1577		p = &hbuf[strlen(hbuf)];
1578		(void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
1579	}
1580
1581#if IP_SRCROUTE
1582postipsr:
1583#endif
1584	if (tTd(9, 1))
1585		printf("getauthinfo: %s\n", hbuf);
1586	return hbuf;
1587}
1588/*
1589**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
1590**
1591**	Parameters:
1592**		map -- a pointer to this map.
1593**		name -- the (presumably unqualified) hostname.
1594**		av -- unused -- for compatibility with other mapping
1595**			functions.
1596**		statp -- an exit status (out parameter) -- set to
1597**			EX_TEMPFAIL if the name server is unavailable.
1598**
1599**	Returns:
1600**		The mapping, if found.
1601**		NULL if no mapping found.
1602**
1603**	Side Effects:
1604**		Looks up the host specified in hbuf.  If it is not
1605**		the canonical name for that host, return the canonical
1606**		name (unless MF_MATCHONLY is set, which will cause the
1607**		status only to be returned).
1608*/
1609
1610char *
1611host_map_lookup(map, name, av, statp)
1612	MAP *map;
1613	char *name;
1614	char **av;
1615	int *statp;
1616{
1617	register struct hostent *hp;
1618	struct in_addr in_addr;
1619	char *cp;
1620	register STAB *s;
1621	char hbuf[MAXNAME + 1];
1622
1623	/*
1624	**  See if we have already looked up this name.  If so, just
1625	**  return it.
1626	*/
1627
1628	s = stab(name, ST_NAMECANON, ST_ENTER);
1629	if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
1630	{
1631		if (tTd(9, 1))
1632			printf("host_map_lookup(%s) => CACHE %s\n",
1633			       name,
1634			       s->s_namecanon.nc_cname == NULL
1635					? "NULL"
1636					: s->s_namecanon.nc_cname);
1637		errno = s->s_namecanon.nc_errno;
1638#if NAMED_BIND
1639		h_errno = s->s_namecanon.nc_herrno;
1640#endif
1641		*statp = s->s_namecanon.nc_stat;
1642		if (*statp == EX_TEMPFAIL)
1643		{
1644			CurEnv->e_status = "4.4.3";
1645			message("851 %s: Name server timeout",
1646				shortenstring(name, 33));
1647		}
1648		if (*statp != EX_OK)
1649			return NULL;
1650		if (s->s_namecanon.nc_cname == NULL)
1651		{
1652			syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
1653				name,
1654				s->s_namecanon.nc_errno,
1655				s->s_namecanon.nc_herrno);
1656			return NULL;
1657		}
1658		if (bitset(MF_MATCHONLY, map->map_mflags))
1659			cp = map_rewrite(map, name, strlen(name), NULL);
1660		else
1661			cp = map_rewrite(map,
1662					 s->s_namecanon.nc_cname,
1663					 strlen(s->s_namecanon.nc_cname),
1664					 av);
1665		return cp;
1666	}
1667
1668	/*
1669	**  If we are running without a regular network connection (usually
1670	**  dial-on-demand) and we are just queueing, we want to avoid DNS
1671	**  lookups because those could try to connect to a server.
1672	*/
1673
1674	if (CurEnv->e_sendmode == SM_DEFER)
1675	{
1676		if (tTd(9, 1))
1677			printf("host_map_lookup(%s) => DEFERRED\n", name);
1678		*statp = EX_TEMPFAIL;
1679		return NULL;
1680	}
1681
1682	/*
1683	**  If first character is a bracket, then it is an address
1684	**  lookup.  Address is copied into a temporary buffer to
1685	**  strip the brackets and to preserve name if address is
1686	**  unknown.
1687	*/
1688
1689	if (*name != '[')
1690	{
1691		if (tTd(9, 1))
1692			printf("host_map_lookup(%s) => ", name);
1693		s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
1694		snprintf(hbuf, sizeof hbuf, "%s", name);
1695		if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
1696		{
1697			if (tTd(9, 1))
1698				printf("%s\n", hbuf);
1699			s->s_namecanon.nc_stat = EX_OK;
1700			s->s_namecanon.nc_cname = newstr(hbuf);
1701			if (bitset(MF_MATCHONLY, map->map_mflags))
1702				cp = map_rewrite(map, name, strlen(name), NULL);
1703			else
1704				cp = map_rewrite(map, hbuf, strlen(hbuf), av);
1705			return cp;
1706		}
1707		else
1708		{
1709			s->s_namecanon.nc_errno = errno;
1710#if NAMED_BIND
1711			s->s_namecanon.nc_herrno = h_errno;
1712			if (tTd(9, 1))
1713				printf("FAIL (%d)\n", h_errno);
1714			switch (h_errno)
1715			{
1716			  case TRY_AGAIN:
1717				if (UseNameServer)
1718				{
1719					CurEnv->e_status = "4.4.3";
1720					message("851 %s: Name server timeout",
1721						shortenstring(name, 33));
1722				}
1723				*statp = EX_TEMPFAIL;
1724				break;
1725
1726			  case HOST_NOT_FOUND:
1727			  case NO_DATA:
1728				*statp = EX_NOHOST;
1729				break;
1730
1731			  case NO_RECOVERY:
1732				*statp = EX_SOFTWARE;
1733				break;
1734
1735			  default:
1736				*statp = EX_UNAVAILABLE;
1737				break;
1738			}
1739#else
1740			if (tTd(9, 1))
1741				printf("FAIL\n");
1742			*statp = EX_NOHOST;
1743#endif
1744			s->s_namecanon.nc_stat = *statp;
1745			return NULL;
1746		}
1747	}
1748	if ((cp = strchr(name, ']')) == NULL)
1749		return (NULL);
1750	*cp = '\0';
1751	in_addr.s_addr = inet_addr(&name[1]);
1752	*cp = ']';
1753
1754	/* nope -- ask the name server */
1755	hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET);
1756	s->s_namecanon.nc_errno = errno;
1757#if NAMED_BIND
1758	s->s_namecanon.nc_herrno = h_errno;
1759#endif
1760	s->s_namecanon.nc_flags |= NCF_VALID;		/* will be soon */
1761	if (hp == NULL)
1762	{
1763		s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1764		return (NULL);
1765	}
1766
1767	/* found a match -- copy out */
1768	hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE);
1769	s->s_namecanon.nc_stat = *statp = EX_OK;
1770	s->s_namecanon.nc_cname = newstr(hp->h_name);
1771	if (bitset(MF_MATCHONLY, map->map_mflags))
1772		cp = map_rewrite(map, name, strlen(name), NULL);
1773	else
1774		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1775	return cp;
1776}
1777
1778# else /* DAEMON */
1779/* code for systems without sophisticated networking */
1780
1781/*
1782**  MYHOSTNAME -- stub version for case of no daemon code.
1783**
1784**	Can't convert to upper case here because might be a UUCP name.
1785**
1786**	Mark, you can change this to be anything you want......
1787*/
1788
1789char **
1790myhostname(hostbuf, size)
1791	char hostbuf[];
1792	int size;
1793{
1794	register FILE *f;
1795
1796	hostbuf[0] = '\0';
1797	f = fopen("/usr/include/whoami", "r");
1798	if (f != NULL)
1799	{
1800		(void) fgets(hostbuf, size, f);
1801		fixcrlf(hostbuf, TRUE);
1802		(void) fclose(f);
1803	}
1804	return (NULL);
1805}
1806/*
1807**  GETAUTHINFO -- get the real host name asociated with a file descriptor
1808**
1809**	Parameters:
1810**		fd -- the descriptor
1811**		may_be_forged -- an outage that is set to TRUE if the
1812**			forward lookup of RealHostName does not match
1813**			RealHostAddr; set to FALSE if they do match.
1814**
1815**	Returns:
1816**		The host name associated with this descriptor, if it can
1817**			be determined.
1818**		NULL otherwise.
1819**
1820**	Side Effects:
1821**		none
1822*/
1823
1824char *
1825getauthinfo(fd, may_be_forged)
1826	int fd;
1827	bool *may_be_forged;
1828{
1829	*may_be_forged = FALSE;
1830	return NULL;
1831}
1832/*
1833**  MAPHOSTNAME -- turn a hostname into canonical form
1834**
1835**	Parameters:
1836**		map -- a pointer to the database map.
1837**		name -- a buffer containing a hostname.
1838**		avp -- a pointer to a (cf file defined) argument vector.
1839**		statp -- an exit status (out parameter).
1840**
1841**	Returns:
1842**		mapped host name
1843**		FALSE otherwise.
1844**
1845**	Side Effects:
1846**		Looks up the host specified in name.  If it is not
1847**		the canonical name for that host, replace it with
1848**		the canonical name.  If the name is unknown, or it
1849**		is already the canonical name, leave it unchanged.
1850*/
1851
1852/*ARGSUSED*/
1853char *
1854host_map_lookup(map, name, avp, statp)
1855	MAP *map;
1856	char *name;
1857	char **avp;
1858	char *statp;
1859{
1860	register struct hostent *hp;
1861	char *cp;
1862
1863	hp = sm_gethostbyname(name);
1864	if (hp == NULL)
1865	{
1866		*statp = EX_NOHOST;
1867		return NULL;
1868	}
1869	if (bitset(MF_MATCHONLY, map->map_mflags))
1870		cp = map_rewrite(map, name, strlen(name), NULL);
1871	else
1872		cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
1873	return cp;
1874}
1875
1876#endif /* DAEMON */
1877/*
1878**  HOST_MAP_INIT -- initialize host class structures
1879*/
1880
1881bool
1882host_map_init(map, args)
1883	MAP *map;
1884	char *args;
1885{
1886	register char *p = args;
1887
1888	for (;;)
1889	{
1890		while (isascii(*p) && isspace(*p))
1891			p++;
1892		if (*p != '-')
1893			break;
1894		switch (*++p)
1895		{
1896		  case 'a':
1897			map->map_app = ++p;
1898			break;
1899
1900		  case 'T':
1901			map->map_tapp = ++p;
1902			break;
1903
1904		  case 'm':
1905			map->map_mflags |= MF_MATCHONLY;
1906			break;
1907
1908		  case 't':
1909			map->map_mflags |= MF_NODEFER;
1910			break;
1911		}
1912		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
1913			p++;
1914		if (*p != '\0')
1915			*p++ = '\0';
1916	}
1917	if (map->map_app != NULL)
1918		map->map_app = newstr(map->map_app);
1919	if (map->map_tapp != NULL)
1920		map->map_tapp = newstr(map->map_tapp);
1921	return TRUE;
1922}
1923/*
1924**  ANYNET_NTOA -- convert a network address to printable form.
1925**
1926**	Parameters:
1927**		sap -- a pointer to a sockaddr structure.
1928**
1929**	Returns:
1930**		A printable version of that sockaddr.
1931*/
1932
1933#ifdef USE_SOCK_STREAM
1934
1935#if NETLINK
1936# include <net/if_dl.h>
1937#endif
1938
1939char *
1940anynet_ntoa(sap)
1941	register SOCKADDR *sap;
1942{
1943	register char *bp;
1944	register char *ap;
1945	int l;
1946	static char buf[100];
1947
1948	/* check for null/zero family */
1949	if (sap == NULL)
1950		return "NULLADDR";
1951	if (sap->sa.sa_family == 0)
1952		return "0";
1953
1954	switch (sap->sa.sa_family)
1955	{
1956#if NETUNIX
1957	  case AF_UNIX:
1958	  	if (sap->sunix.sun_path[0] != '\0')
1959	  		snprintf(buf, sizeof buf, "[UNIX: %.64s]",
1960				sap->sunix.sun_path);
1961	  	else
1962	  		snprintf(buf, sizeof buf, "[UNIX: localhost]");
1963		return buf;
1964#endif
1965
1966#if NETINET
1967	  case AF_INET:
1968		return inet_ntoa(sap->sin.sin_addr);
1969#endif
1970
1971#if NETLINK
1972	  case AF_LINK:
1973		snprintf(buf, sizeof buf, "[LINK: %s]",
1974			link_ntoa((struct sockaddr_dl *) &sap->sa));
1975		return buf;
1976#endif
1977	  default:
1978		/* this case is needed when nothing is #defined */
1979		/* in order to keep the switch syntactically correct */
1980		break;
1981	}
1982
1983	/* unknown family -- just dump bytes */
1984	(void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
1985	bp = &buf[strlen(buf)];
1986	ap = sap->sa.sa_data;
1987	for (l = sizeof sap->sa.sa_data; --l >= 0; )
1988	{
1989		(void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
1990		bp += 3;
1991	}
1992	*--bp = '\0';
1993	return buf;
1994}
1995/*
1996**  HOSTNAMEBYANYADDR -- return name of host based on address
1997**
1998**	Parameters:
1999**		sap -- SOCKADDR pointer
2000**
2001**	Returns:
2002**		text representation of host name.
2003**
2004**	Side Effects:
2005**		none.
2006*/
2007
2008char *
2009hostnamebyanyaddr(sap)
2010	register SOCKADDR *sap;
2011{
2012	register struct hostent *hp;
2013	int saveretry;
2014
2015#if NAMED_BIND
2016	/* shorten name server timeout to avoid higher level timeouts */
2017	saveretry = _res.retry;
2018	_res.retry = 3;
2019#endif /* NAMED_BIND */
2020
2021	switch (sap->sa.sa_family)
2022	{
2023#if NETINET
2024	  case AF_INET:
2025		hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
2026			INADDRSZ,
2027			AF_INET);
2028		break;
2029#endif
2030
2031#if NETISO
2032	  case AF_ISO:
2033		hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
2034			sizeof sap->siso.siso_addr,
2035			AF_ISO);
2036		break;
2037#endif
2038
2039#if NETUNIX
2040	  case AF_UNIX:
2041		hp = NULL;
2042		break;
2043#endif
2044
2045	  default:
2046		hp = sm_gethostbyaddr(sap->sa.sa_data,
2047			   sizeof sap->sa.sa_data,
2048			   sap->sa.sa_family);
2049		break;
2050	}
2051
2052#if NAMED_BIND
2053	_res.retry = saveretry;
2054#endif /* NAMED_BIND */
2055
2056	if (hp != NULL && hp->h_name[0] != '[' &&
2057	    inet_addr(hp->h_name) == INADDR_NONE)
2058		return denlstring((char *) hp->h_name, TRUE, TRUE);
2059#if NETUNIX
2060	else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
2061		return "localhost";
2062#endif
2063	else
2064	{
2065		/* produce a dotted quad */
2066		static char buf[203];
2067
2068		(void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
2069		return buf;
2070	}
2071}
2072
2073#endif /* SOCK_STREAM */
2074