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