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