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