listener.c revision 261363
1230557Sjimharris/*
2230557Sjimharris *  Copyright (c) 1999-2007 Proofpoint, Inc. and its suppliers.
3230557Sjimharris *	All rights reserved.
4230557Sjimharris *
5230557Sjimharris * By using this file, you agree to the terms and conditions set
6230557Sjimharris * forth in the LICENSE file which can be found at the top level of
7230557Sjimharris * the sendmail distribution.
8230557Sjimharris *
9230557Sjimharris */
10230557Sjimharris
11230557Sjimharris#include <sm/gen.h>
12230557SjimharrisSM_RCSID("@(#)$Id: listener.c,v 8.127 2013/11/22 20:51:36 ca Exp $")
13230557Sjimharris
14230557Sjimharris/*
15230557Sjimharris**  listener.c -- threaded network listener
16230557Sjimharris*/
17230557Sjimharris
18230557Sjimharris#include "libmilter.h"
19230557Sjimharris#include <sm/errstring.h>
20230557Sjimharris
21230557Sjimharris#include <sys/types.h>
22230557Sjimharris#include <sys/stat.h>
23230557Sjimharris
24230557Sjimharris
25230557Sjimharris# if NETINET || NETINET6
26230557Sjimharris#  include <arpa/inet.h>
27230557Sjimharris# endif /* NETINET || NETINET6 */
28230557Sjimharris# if SM_CONF_POLL
29230557Sjimharris#  undef SM_FD_OK_SELECT
30230557Sjimharris#  define SM_FD_OK_SELECT(fd)		true
31230557Sjimharris# endif /* SM_CONF_POLL */
32230557Sjimharris
33230557Sjimharrisstatic smutex_t L_Mutex;
34230557Sjimharrisstatic int L_family;
35230557Sjimharrisstatic SOCKADDR_LEN_T L_socksize;
36230557Sjimharrisstatic socket_t listenfd = INVALID_SOCKET;
37230557Sjimharris
38230557Sjimharrisstatic socket_t mi_milteropen __P((char *, int, bool, char *));
39230557Sjimharris#if !_FFR_WORKERS_POOL
40230557Sjimharrisstatic void *mi_thread_handle_wrapper __P((void *));
41230557Sjimharris#endif /* !_FFR_WORKERS_POOL */
42230557Sjimharris
43230557Sjimharris/*
44230557Sjimharris**  MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
45230557Sjimharris**
46230557Sjimharris**	Parameters:
47230557Sjimharris**		conn -- connection description
48230557Sjimharris**		backlog -- listen backlog
49230557Sjimharris**		dbg -- debug level
50230557Sjimharris**		rmsocket -- if true, try to unlink() the socket first
51230557Sjimharris**			(UNIX domain sockets only)
52230557Sjimharris**		smfi -- filter structure to use
53230557Sjimharris**
54230557Sjimharris**	Return value:
55230557Sjimharris**		MI_SUCCESS/MI_FAILURE
56230557Sjimharris*/
57230557Sjimharris
58230557Sjimharrisint
59230557Sjimharrismi_opensocket(conn, backlog, dbg, rmsocket, smfi)
60230557Sjimharris	char *conn;
61230557Sjimharris	int backlog;
62230557Sjimharris	int dbg;
63230557Sjimharris	bool rmsocket;
64230557Sjimharris	smfiDesc_ptr smfi;
65230557Sjimharris{
66230557Sjimharris	if (smfi == NULL || conn == NULL)
67230557Sjimharris		return MI_FAILURE;
68230557Sjimharris
69230557Sjimharris	if (ValidSocket(listenfd))
70230557Sjimharris		return MI_SUCCESS;
71230557Sjimharris
72230557Sjimharris	if (dbg > 0)
73230557Sjimharris	{
74230557Sjimharris		smi_log(SMI_LOG_DEBUG,
75230557Sjimharris			"%s: Opening listen socket on conn %s",
76230557Sjimharris			smfi->xxfi_name, conn);
77230557Sjimharris	}
78230557Sjimharris	(void) smutex_init(&L_Mutex);
79230557Sjimharris	(void) smutex_lock(&L_Mutex);
80230557Sjimharris	listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name);
81230557Sjimharris	if (!ValidSocket(listenfd))
82230557Sjimharris	{
83230557Sjimharris		smi_log(SMI_LOG_FATAL,
84230557Sjimharris			"%s: Unable to create listening socket on conn %s",
85230557Sjimharris			smfi->xxfi_name, conn);
86230557Sjimharris		(void) smutex_unlock(&L_Mutex);
87230557Sjimharris		return MI_FAILURE;
88230557Sjimharris	}
89230557Sjimharris	if (!SM_FD_OK_SELECT(listenfd))
90230557Sjimharris	{
91230557Sjimharris		smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
92230557Sjimharris			smfi->xxfi_name, listenfd, FD_SETSIZE);
93230557Sjimharris		(void) smutex_unlock(&L_Mutex);
94230557Sjimharris		return MI_FAILURE;
95230557Sjimharris	}
96230557Sjimharris	(void) smutex_unlock(&L_Mutex);
97230557Sjimharris	return MI_SUCCESS;
98230557Sjimharris}
99230557Sjimharris
100230557Sjimharris/*
101230557Sjimharris**  MI_MILTEROPEN -- setup socket to listen on
102230557Sjimharris**
103230557Sjimharris**	Parameters:
104230557Sjimharris**		conn -- connection description
105230557Sjimharris**		backlog -- listen backlog
106230557Sjimharris**		rmsocket -- if true, try to unlink() the socket first
107230557Sjimharris**			(UNIX domain sockets only)
108230557Sjimharris**		name -- name for logging
109230557Sjimharris**
110230557Sjimharris**	Returns:
111230557Sjimharris**		socket upon success, error code otherwise.
112230557Sjimharris**
113230557Sjimharris**	Side effect:
114230557Sjimharris**		sets sockpath if UNIX socket.
115230557Sjimharris*/
116230557Sjimharris
117230557Sjimharris#if NETUNIX
118230557Sjimharrisstatic char	*sockpath = NULL;
119230557Sjimharris#endif /* NETUNIX */
120230557Sjimharris
121230557Sjimharrisstatic socket_t
122230557Sjimharrismi_milteropen(conn, backlog, rmsocket, name)
123230557Sjimharris	char *conn;
124230557Sjimharris	int backlog;
125230557Sjimharris	bool rmsocket;
126230557Sjimharris	char *name;
127230557Sjimharris{
128230557Sjimharris	socket_t sock;
129230557Sjimharris	int sockopt = 1;
130230557Sjimharris	int fdflags;
131230557Sjimharris	size_t len = 0;
132230557Sjimharris	char *p;
133230557Sjimharris	char *colon;
134230557Sjimharris	char *at;
135230557Sjimharris	SOCKADDR addr;
136230557Sjimharris
137230557Sjimharris	if (conn == NULL || conn[0] == '\0')
138230557Sjimharris	{
139230557Sjimharris		smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
140230557Sjimharris			name);
141230557Sjimharris		return INVALID_SOCKET;
142230557Sjimharris	}
143230557Sjimharris	(void) memset(&addr, '\0', sizeof addr);
144230557Sjimharris
145230557Sjimharris	/* protocol:filename or protocol:port@host */
146230557Sjimharris	p = conn;
147230557Sjimharris	colon = strchr(p, ':');
148230557Sjimharris	if (colon != NULL)
149230557Sjimharris	{
150230557Sjimharris		*colon = '\0';
151230557Sjimharris
152230557Sjimharris		if (*p == '\0')
153230557Sjimharris		{
154230557Sjimharris#if NETUNIX
155230557Sjimharris			/* default to AF_UNIX */
156230557Sjimharris			addr.sa.sa_family = AF_UNIX;
157230557Sjimharris			L_socksize = sizeof (struct sockaddr_un);
158230557Sjimharris#else /* NETUNIX */
159230557Sjimharris# if NETINET
160230557Sjimharris			/* default to AF_INET */
161230557Sjimharris			addr.sa.sa_family = AF_INET;
162230557Sjimharris			L_socksize = sizeof addr.sin;
163230557Sjimharris# else /* NETINET */
164230557Sjimharris#  if NETINET6
165230557Sjimharris			/* default to AF_INET6 */
166230557Sjimharris			addr.sa.sa_family = AF_INET6;
167230557Sjimharris			L_socksize = sizeof addr.sin6;
168230557Sjimharris#  else /* NETINET6 */
169230557Sjimharris			/* no protocols available */
170230557Sjimharris			smi_log(SMI_LOG_ERR,
171230557Sjimharris				"%s: no valid socket protocols available",
172230557Sjimharris				name);
173230557Sjimharris			return INVALID_SOCKET;
174230557Sjimharris#  endif /* NETINET6 */
175230557Sjimharris# endif /* NETINET */
176230557Sjimharris#endif /* NETUNIX */
177230557Sjimharris		}
178230557Sjimharris#if NETUNIX
179230557Sjimharris		else if (strcasecmp(p, "unix") == 0 ||
180230557Sjimharris			 strcasecmp(p, "local") == 0)
181230557Sjimharris		{
182230557Sjimharris			addr.sa.sa_family = AF_UNIX;
183230557Sjimharris			L_socksize = sizeof (struct sockaddr_un);
184230557Sjimharris		}
185230557Sjimharris#endif /* NETUNIX */
186230557Sjimharris#if NETINET
187230557Sjimharris		else if (strcasecmp(p, "inet") == 0)
188230557Sjimharris		{
189230557Sjimharris			addr.sa.sa_family = AF_INET;
190230557Sjimharris			L_socksize = sizeof addr.sin;
191230557Sjimharris		}
192230557Sjimharris#endif /* NETINET */
193230557Sjimharris#if NETINET6
194230557Sjimharris		else if (strcasecmp(p, "inet6") == 0)
195230557Sjimharris		{
196230557Sjimharris			addr.sa.sa_family = AF_INET6;
197230557Sjimharris			L_socksize = sizeof addr.sin6;
198230557Sjimharris		}
199230557Sjimharris#endif /* NETINET6 */
200230557Sjimharris		else
201230557Sjimharris		{
202230557Sjimharris			smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
203230557Sjimharris				name, p);
204230557Sjimharris			return INVALID_SOCKET;
205230557Sjimharris		}
206230557Sjimharris		*colon++ = ':';
207230557Sjimharris	}
208230557Sjimharris	else
209230557Sjimharris	{
210230557Sjimharris		colon = p;
211230557Sjimharris#if NETUNIX
212230557Sjimharris		/* default to AF_UNIX */
213230557Sjimharris		addr.sa.sa_family = AF_UNIX;
214230557Sjimharris		L_socksize = sizeof (struct sockaddr_un);
215230557Sjimharris#else /* NETUNIX */
216230557Sjimharris# if NETINET
217230557Sjimharris		/* default to AF_INET */
218230557Sjimharris		addr.sa.sa_family = AF_INET;
219230557Sjimharris		L_socksize = sizeof addr.sin;
220230557Sjimharris# else /* NETINET */
221230557Sjimharris#  if NETINET6
222230557Sjimharris		/* default to AF_INET6 */
223230557Sjimharris		addr.sa.sa_family = AF_INET6;
224230557Sjimharris		L_socksize = sizeof addr.sin6;
225230557Sjimharris#  else /* NETINET6 */
226230557Sjimharris		smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
227230557Sjimharris			name, p);
228230557Sjimharris		return INVALID_SOCKET;
229230557Sjimharris#  endif /* NETINET6 */
230230557Sjimharris# endif /* NETINET */
231230557Sjimharris#endif /* NETUNIX */
232230557Sjimharris	}
233230557Sjimharris
234230557Sjimharris#if NETUNIX
235230557Sjimharris	if (addr.sa.sa_family == AF_UNIX)
236230557Sjimharris	{
237230557Sjimharris# if 0
238230557Sjimharris		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
239230557Sjimharris# endif /* 0 */
240230557Sjimharris
241230557Sjimharris		at = colon;
242230557Sjimharris		len = strlen(colon) + 1;
243230557Sjimharris		if (len >= sizeof addr.sunix.sun_path)
244230557Sjimharris		{
245230557Sjimharris			errno = EINVAL;
246230557Sjimharris			smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
247230557Sjimharris				name, colon);
248230557Sjimharris			return INVALID_SOCKET;
249230557Sjimharris		}
250230557Sjimharris		(void) sm_strlcpy(addr.sunix.sun_path, colon,
251230557Sjimharris				sizeof addr.sunix.sun_path);
252230557Sjimharris# if 0
253230557Sjimharris		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
254230557Sjimharris				 S_IRUSR|S_IWUSR, NULL);
255230557Sjimharris
256230557Sjimharris		/* if not safe, don't create */
257230557Sjimharris		if (errno != 0)
258230557Sjimharris		{
259230557Sjimharris			smi_log(SMI_LOG_ERR,
260230557Sjimharris				"%s: UNIX socket name %s unsafe",
261230557Sjimharris				name, colon);
262230557Sjimharris			return INVALID_SOCKET;
263230557Sjimharris		}
264230557Sjimharris# endif /* 0 */
265230557Sjimharris	}
266230557Sjimharris#endif /* NETUNIX */
267230557Sjimharris
268230557Sjimharris#if NETINET || NETINET6
269230557Sjimharris	if (
270230557Sjimharris# if NETINET
271230557Sjimharris	    addr.sa.sa_family == AF_INET
272230557Sjimharris# endif /* NETINET */
273230557Sjimharris# if NETINET && NETINET6
274230557Sjimharris	    ||
275230557Sjimharris# endif /* NETINET && NETINET6 */
276230557Sjimharris# if NETINET6
277230557Sjimharris	    addr.sa.sa_family == AF_INET6
278230557Sjimharris# endif /* NETINET6 */
279230557Sjimharris	   )
280230557Sjimharris	{
281230557Sjimharris		unsigned short port;
282230557Sjimharris
283230557Sjimharris		/* Parse port@host */
284230557Sjimharris		at = strchr(colon, '@');
285230557Sjimharris		if (at == NULL)
286230557Sjimharris		{
287230557Sjimharris			switch (addr.sa.sa_family)
288230557Sjimharris			{
289230557Sjimharris# if NETINET
290230557Sjimharris			  case AF_INET:
291230557Sjimharris				addr.sin.sin_addr.s_addr = INADDR_ANY;
292230557Sjimharris				break;
293230557Sjimharris# endif /* NETINET */
294230557Sjimharris
295230557Sjimharris# if NETINET6
296230557Sjimharris			  case AF_INET6:
297230557Sjimharris				addr.sin6.sin6_addr = in6addr_any;
298230557Sjimharris				break;
299230557Sjimharris# endif /* NETINET6 */
300230557Sjimharris			}
301230557Sjimharris		}
302230557Sjimharris		else
303230557Sjimharris			*at = '\0';
304230557Sjimharris
305230557Sjimharris		if (isascii(*colon) && isdigit(*colon))
306230557Sjimharris			port = htons((unsigned short) atoi(colon));
307230557Sjimharris		else
308230557Sjimharris		{
309230557Sjimharris# ifdef NO_GETSERVBYNAME
310230557Sjimharris			smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
311230557Sjimharris				name, colon);
312230557Sjimharris			return INVALID_SOCKET;
313230557Sjimharris# else /* NO_GETSERVBYNAME */
314230557Sjimharris			register struct servent *sp;
315230557Sjimharris
316230557Sjimharris			sp = getservbyname(colon, "tcp");
317230557Sjimharris			if (sp == NULL)
318230557Sjimharris			{
319230557Sjimharris				smi_log(SMI_LOG_ERR,
320230557Sjimharris					"%s: unknown port name %s",
321230557Sjimharris					name, colon);
322230557Sjimharris				return INVALID_SOCKET;
323230557Sjimharris			}
324230557Sjimharris			port = sp->s_port;
325230557Sjimharris# endif /* NO_GETSERVBYNAME */
326230557Sjimharris		}
327230557Sjimharris		if (at != NULL)
328230557Sjimharris		{
329230557Sjimharris			*at++ = '@';
330230557Sjimharris			if (*at == '[')
331230557Sjimharris			{
332230557Sjimharris				char *end;
333230557Sjimharris
334230557Sjimharris				end = strchr(at, ']');
335230557Sjimharris				if (end != NULL)
336230557Sjimharris				{
337230557Sjimharris					bool found = false;
338230557Sjimharris# if NETINET
339230557Sjimharris					unsigned long hid = INADDR_NONE;
340230557Sjimharris# endif /* NETINET */
341230557Sjimharris# if NETINET6
342230557Sjimharris					struct sockaddr_in6 hid6;
343230557Sjimharris# endif /* NETINET6 */
344230557Sjimharris
345230557Sjimharris					*end = '\0';
346230557Sjimharris# if NETINET
347230557Sjimharris					if (addr.sa.sa_family == AF_INET &&
348230557Sjimharris					    (hid = inet_addr(&at[1])) != INADDR_NONE)
349230557Sjimharris					{
350230557Sjimharris						addr.sin.sin_addr.s_addr = hid;
351230557Sjimharris						addr.sin.sin_port = port;
352230557Sjimharris						found = true;
353230557Sjimharris					}
354230557Sjimharris# endif /* NETINET */
355230557Sjimharris# if NETINET6
356230557Sjimharris					(void) memset(&hid6, '\0', sizeof hid6);
357230557Sjimharris					if (addr.sa.sa_family == AF_INET6 &&
358230557Sjimharris					    mi_inet_pton(AF_INET6, &at[1],
359230557Sjimharris							 &hid6.sin6_addr) == 1)
360230557Sjimharris					{
361230557Sjimharris						addr.sin6.sin6_addr = hid6.sin6_addr;
362230557Sjimharris						addr.sin6.sin6_port = port;
363230557Sjimharris						found = true;
364230557Sjimharris					}
365230557Sjimharris# endif /* NETINET6 */
366230557Sjimharris					*end = ']';
367230557Sjimharris					if (!found)
368230557Sjimharris					{
369230557Sjimharris						smi_log(SMI_LOG_ERR,
370230557Sjimharris							"%s: Invalid numeric domain spec \"%s\"",
371230557Sjimharris							name, at);
372230557Sjimharris						return INVALID_SOCKET;
373230557Sjimharris					}
374230557Sjimharris				}
375230557Sjimharris				else
376230557Sjimharris				{
377230557Sjimharris					smi_log(SMI_LOG_ERR,
378230557Sjimharris						"%s: Invalid numeric domain spec \"%s\"",
379230557Sjimharris						name, at);
380230557Sjimharris					return INVALID_SOCKET;
381230557Sjimharris				}
382230557Sjimharris			}
383230557Sjimharris			else
384230557Sjimharris			{
385230557Sjimharris				struct hostent *hp = NULL;
386230557Sjimharris
387230557Sjimharris				hp = mi_gethostbyname(at, addr.sa.sa_family);
388230557Sjimharris				if (hp == NULL)
389230557Sjimharris				{
390230557Sjimharris					smi_log(SMI_LOG_ERR,
391230557Sjimharris						"%s: Unknown host name %s",
392230557Sjimharris						name, at);
393230557Sjimharris					return INVALID_SOCKET;
394230557Sjimharris				}
395230557Sjimharris				addr.sa.sa_family = hp->h_addrtype;
396230557Sjimharris				switch (hp->h_addrtype)
397230557Sjimharris				{
398230557Sjimharris# if NETINET
399230557Sjimharris				  case AF_INET:
400230557Sjimharris					(void) memmove(&addr.sin.sin_addr,
401230557Sjimharris						       hp->h_addr,
402230557Sjimharris						       INADDRSZ);
403230557Sjimharris					addr.sin.sin_port = port;
404230557Sjimharris					break;
405230557Sjimharris# endif /* NETINET */
406230557Sjimharris
407230557Sjimharris# if NETINET6
408230557Sjimharris				  case AF_INET6:
409230557Sjimharris					(void) memmove(&addr.sin6.sin6_addr,
410230557Sjimharris						       hp->h_addr,
411230557Sjimharris						       IN6ADDRSZ);
412230557Sjimharris					addr.sin6.sin6_port = port;
413230557Sjimharris					break;
414230557Sjimharris# endif /* NETINET6 */
415230557Sjimharris
416230557Sjimharris				  default:
417230557Sjimharris					smi_log(SMI_LOG_ERR,
418230557Sjimharris						"%s: Unknown protocol for %s (%d)",
419230557Sjimharris						name, at, hp->h_addrtype);
420230557Sjimharris					return INVALID_SOCKET;
421230557Sjimharris				}
422230557Sjimharris# if NETINET6
423230557Sjimharris				freehostent(hp);
424230557Sjimharris# endif /* NETINET6 */
425230557Sjimharris			}
426230557Sjimharris		}
427230557Sjimharris		else
428230557Sjimharris		{
429230557Sjimharris			switch (addr.sa.sa_family)
430230557Sjimharris			{
431230557Sjimharris# if NETINET
432230557Sjimharris			  case AF_INET:
433230557Sjimharris				addr.sin.sin_port = port;
434230557Sjimharris				break;
435230557Sjimharris# endif /* NETINET */
436230557Sjimharris# if NETINET6
437230557Sjimharris			  case AF_INET6:
438230557Sjimharris				addr.sin6.sin6_port = port;
439230557Sjimharris				break;
440230557Sjimharris# endif /* NETINET6 */
441230557Sjimharris			}
442230557Sjimharris		}
443230557Sjimharris	}
444230557Sjimharris#endif /* NETINET || NETINET6 */
445230557Sjimharris
446230557Sjimharris	sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
447230557Sjimharris	if (!ValidSocket(sock))
448230557Sjimharris	{
449230557Sjimharris		smi_log(SMI_LOG_ERR,
450230557Sjimharris			"%s: Unable to create new socket: %s",
451230557Sjimharris			name, sm_errstring(errno));
452230557Sjimharris		return INVALID_SOCKET;
453230557Sjimharris	}
454230557Sjimharris
455230557Sjimharris	if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
456230557Sjimharris	    fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
457230557Sjimharris	{
458230557Sjimharris		smi_log(SMI_LOG_ERR,
459230557Sjimharris			"%s: Unable to set close-on-exec: %s", name,
460230557Sjimharris			sm_errstring(errno));
461230557Sjimharris		(void) closesocket(sock);
462230557Sjimharris		return INVALID_SOCKET;
463230557Sjimharris	}
464230557Sjimharris
465230557Sjimharris	if (
466230557Sjimharris#if NETUNIX
467230557Sjimharris	    addr.sa.sa_family != AF_UNIX &&
468230557Sjimharris#endif /* NETUNIX */
469230557Sjimharris	    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
470230557Sjimharris		       sizeof(sockopt)) == -1)
471230557Sjimharris	{
472230557Sjimharris		smi_log(SMI_LOG_ERR,
473230557Sjimharris			"%s: set reuseaddr failed (%s)", name,
474230557Sjimharris			sm_errstring(errno));
475230557Sjimharris		(void) closesocket(sock);
476230557Sjimharris		return INVALID_SOCKET;
477230557Sjimharris	}
478230557Sjimharris
479230557Sjimharris#if NETUNIX
480230557Sjimharris	if (addr.sa.sa_family == AF_UNIX && rmsocket)
481230557Sjimharris	{
482230557Sjimharris		struct stat s;
483230557Sjimharris
484230557Sjimharris		if (stat(colon, &s) != 0)
485230557Sjimharris		{
486230557Sjimharris			if (errno != ENOENT)
487230557Sjimharris			{
488230557Sjimharris				smi_log(SMI_LOG_ERR,
489230557Sjimharris					"%s: Unable to stat() %s: %s",
490230557Sjimharris					name, colon, sm_errstring(errno));
491230557Sjimharris				(void) closesocket(sock);
492230557Sjimharris				return INVALID_SOCKET;
493230557Sjimharris			}
494230557Sjimharris		}
495230557Sjimharris		else if (!S_ISSOCK(s.st_mode))
496230557Sjimharris		{
497230557Sjimharris			smi_log(SMI_LOG_ERR,
498230557Sjimharris				"%s: %s is not a UNIX domain socket",
499230557Sjimharris				name, colon);
500230557Sjimharris			(void) closesocket(sock);
501230557Sjimharris			return INVALID_SOCKET;
502230557Sjimharris		}
503		else if (unlink(colon) != 0)
504		{
505			smi_log(SMI_LOG_ERR,
506				"%s: Unable to remove %s: %s",
507				name, colon, sm_errstring(errno));
508			(void) closesocket(sock);
509			return INVALID_SOCKET;
510		}
511	}
512#endif /* NETUNIX */
513
514	if (bind(sock, &addr.sa, L_socksize) < 0)
515	{
516		smi_log(SMI_LOG_ERR,
517			"%s: Unable to bind to port %s: %s",
518			name, conn, sm_errstring(errno));
519		(void) closesocket(sock);
520		return INVALID_SOCKET;
521	}
522
523	if (listen(sock, backlog) < 0)
524	{
525		smi_log(SMI_LOG_ERR,
526			"%s: listen call failed: %s", name,
527			sm_errstring(errno));
528		(void) closesocket(sock);
529		return INVALID_SOCKET;
530	}
531
532#if NETUNIX
533	if (addr.sa.sa_family == AF_UNIX && len > 0)
534	{
535		/*
536		**  Set global variable sockpath so the UNIX socket can be
537		**  unlink()ed at exit.
538		*/
539
540		sockpath = (char *) malloc(len);
541		if (sockpath != NULL)
542			(void) sm_strlcpy(sockpath, colon, len);
543		else
544		{
545			smi_log(SMI_LOG_ERR,
546				"%s: can't malloc(%d) for sockpath: %s",
547				name, (int) len, sm_errstring(errno));
548			(void) closesocket(sock);
549			return INVALID_SOCKET;
550		}
551	}
552#endif /* NETUNIX */
553	L_family = addr.sa.sa_family;
554	return sock;
555}
556
557#if !_FFR_WORKERS_POOL
558/*
559**  MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
560**
561**	Parameters:
562**		arg -- argument to pass to mi_handle_session()
563**
564**	Returns:
565**		results from mi_handle_session()
566*/
567
568static void *
569mi_thread_handle_wrapper(arg)
570	void *arg;
571{
572	/*
573	**  Note: on some systems this generates a compiler warning:
574	**  cast to pointer from integer of different size
575	**  You can safely ignore this warning as the result of this function
576	**  is not used anywhere.
577	*/
578
579	return (void *) mi_handle_session(arg);
580}
581#endif /* _FFR_WORKERS_POOL */
582
583/*
584**  MI_CLOSENER -- close listen socket
585**
586**	Parameters:
587**		none.
588**
589**	Returns:
590**		none.
591*/
592
593void
594mi_closener()
595{
596	(void) smutex_lock(&L_Mutex);
597	if (ValidSocket(listenfd))
598	{
599#if NETUNIX
600		bool removable;
601		struct stat sockinfo;
602		struct stat fileinfo;
603
604		removable = sockpath != NULL &&
605			    geteuid() != 0 &&
606			    fstat(listenfd, &sockinfo) == 0 &&
607			    (S_ISFIFO(sockinfo.st_mode)
608# ifdef S_ISSOCK
609			     || S_ISSOCK(sockinfo.st_mode)
610# endif /* S_ISSOCK */
611			    );
612#endif /* NETUNIX */
613
614		(void) closesocket(listenfd);
615		listenfd = INVALID_SOCKET;
616
617#if NETUNIX
618		/* XXX sleep() some time before doing this? */
619		if (sockpath != NULL)
620		{
621			if (removable &&
622			    stat(sockpath, &fileinfo) == 0 &&
623			    ((fileinfo.st_dev == sockinfo.st_dev &&
624			      fileinfo.st_ino == sockinfo.st_ino)
625# ifdef S_ISSOCK
626			     || S_ISSOCK(fileinfo.st_mode)
627# endif /* S_ISSOCK */
628			    )
629			    &&
630			    (S_ISFIFO(fileinfo.st_mode)
631# ifdef S_ISSOCK
632			     || S_ISSOCK(fileinfo.st_mode)
633# endif /* S_ISSOCK */
634			     ))
635				(void) unlink(sockpath);
636			free(sockpath);
637			sockpath = NULL;
638		}
639#endif /* NETUNIX */
640	}
641	(void) smutex_unlock(&L_Mutex);
642}
643
644/*
645**  MI_LISTENER -- Generic listener harness
646**
647**	Open up listen port
648**	Wait for connections
649**
650**	Parameters:
651**		conn -- connection description
652**		dbg -- debug level
653**		smfi -- filter structure to use
654**		timeout -- timeout for reads/writes
655**		backlog -- listen queue backlog size
656**
657**	Returns:
658**		MI_SUCCESS -- Exited normally
659**			   (session finished or we were told to exit)
660**		MI_FAILURE -- Network initialization failed.
661*/
662
663#if BROKEN_PTHREAD_SLEEP
664
665/*
666**  Solaris 2.6, perhaps others, gets an internal threads library panic
667**  when sleep() is used:
668**
669**  thread_create() failed, returned 11 (EINVAL)
670**  co_enable, thr_create() returned error = 24
671**  libthread panic: co_enable failed (PID: 17793 LWP 1)
672**  stacktrace:
673**	ef526b10
674**	ef52646c
675**	ef534cbc
676**	156a4
677**	14644
678**	1413c
679**	135e0
680**	0
681*/
682
683# define MI_SLEEP(s)							\
684{									\
685	int rs = 0;							\
686	struct timeval st;						\
687									\
688	st.tv_sec = (s);						\
689	st.tv_usec = 0;							\
690	if (st.tv_sec > 0)						\
691	{								\
692		for (;;)						\
693		{							\
694			rs = select(0, NULL, NULL, NULL, &st);		\
695			if (rs < 0 && errno == EINTR)			\
696				continue;				\
697			if (rs != 0)					\
698			{						\
699				smi_log(SMI_LOG_ERR,			\
700					"MI_SLEEP(): select() returned non-zero result %d, errno = %d",	\
701					rs, errno);			\
702			}						\
703			break;						\
704		}							\
705	}								\
706}
707#else /* BROKEN_PTHREAD_SLEEP */
708# define MI_SLEEP(s)	sleep((s))
709#endif /* BROKEN_PTHREAD_SLEEP */
710
711int
712mi_listener(conn, dbg, smfi, timeout, backlog)
713	char *conn;
714	int dbg;
715	smfiDesc_ptr smfi;
716	time_t timeout;
717	int backlog;
718{
719	socket_t connfd = INVALID_SOCKET;
720#if _FFR_DUP_FD
721	socket_t dupfd = INVALID_SOCKET;
722#endif /* _FFR_DUP_FD */
723	int sockopt = 1;
724	int r, mistop;
725	int ret = MI_SUCCESS;
726	int mcnt = 0;	/* error count for malloc() failures */
727	int tcnt = 0;	/* error count for thread_create() failures */
728	int acnt = 0;	/* error count for accept() failures */
729	int scnt = 0;	/* error count for select() failures */
730	int save_errno = 0;
731#if !_FFR_WORKERS_POOL
732	sthread_t thread_id;
733#endif /* !_FFR_WORKERS_POOL */
734	_SOCK_ADDR cliaddr;
735	SOCKADDR_LEN_T clilen;
736	SMFICTX_PTR ctx;
737	FD_RD_VAR(rds, excs);
738	struct timeval chktime;
739
740	if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
741		return MI_FAILURE;
742
743#if _FFR_WORKERS_POOL
744	if (mi_pool_controller_init() == MI_FAILURE)
745		return MI_FAILURE;
746#endif /* _FFR_WORKERS_POOL */
747
748	clilen = L_socksize;
749	while ((mistop = mi_stop()) == MILTER_CONT)
750	{
751		(void) smutex_lock(&L_Mutex);
752		if (!ValidSocket(listenfd))
753		{
754			ret = MI_FAILURE;
755			smi_log(SMI_LOG_ERR,
756				"%s: listenfd=%d corrupted, terminating, errno=%d",
757				smfi->xxfi_name, listenfd, errno);
758			(void) smutex_unlock(&L_Mutex);
759			break;
760		}
761
762		/* select on interface ports */
763		FD_RD_INIT(listenfd, rds, excs);
764		chktime.tv_sec = MI_CHK_TIME;
765		chktime.tv_usec = 0;
766		r = FD_RD_READY(listenfd, rds, excs, &chktime);
767		if (r == 0)		/* timeout */
768		{
769			(void) smutex_unlock(&L_Mutex);
770			continue;	/* just check mi_stop() */
771		}
772		if (r < 0)
773		{
774			save_errno = errno;
775			(void) smutex_unlock(&L_Mutex);
776			if (save_errno == EINTR)
777				continue;
778			scnt++;
779			smi_log(SMI_LOG_ERR,
780				"%s: %s() failed (%s), %s",
781				smfi->xxfi_name, MI_POLLSELECT,
782				sm_errstring(save_errno),
783				scnt >= MAX_FAILS_S ? "abort" : "try again");
784			MI_SLEEP(scnt);
785			if (scnt >= MAX_FAILS_S)
786			{
787				ret = MI_FAILURE;
788				break;
789			}
790			continue;
791		}
792		if (!FD_IS_RD_RDY(listenfd, rds, excs))
793		{
794			/* some error: just stop for now... */
795			ret = MI_FAILURE;
796			(void) smutex_unlock(&L_Mutex);
797			smi_log(SMI_LOG_ERR,
798				"%s: %s() returned exception for socket, abort",
799				smfi->xxfi_name, MI_POLLSELECT);
800			break;
801		}
802		scnt = 0;	/* reset error counter for select() */
803
804		(void) memset(&cliaddr, '\0', sizeof cliaddr);
805		connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
806				&clilen);
807		save_errno = errno;
808		(void) smutex_unlock(&L_Mutex);
809
810		/*
811		**  If remote side closes before accept() finishes,
812		**  sockaddr might not be fully filled in.
813		*/
814
815		if (ValidSocket(connfd) &&
816		    (clilen == 0 ||
817# ifdef BSD4_4_SOCKADDR
818		     cliaddr.sa.sa_len == 0 ||
819# endif /* BSD4_4_SOCKADDR */
820		     cliaddr.sa.sa_family != L_family))
821		{
822			(void) closesocket(connfd);
823			connfd = INVALID_SOCKET;
824			save_errno = EINVAL;
825		}
826
827		/* check if acceptable for select() */
828		if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
829		{
830			(void) closesocket(connfd);
831			connfd = INVALID_SOCKET;
832			save_errno = ERANGE;
833		}
834
835		if (!ValidSocket(connfd))
836		{
837			if (save_errno == EINTR
838#ifdef EAGAIN
839			    || save_errno == EAGAIN
840#endif /* EAGAIN */
841#ifdef ECONNABORTED
842			    || save_errno == ECONNABORTED
843#endif /* ECONNABORTED */
844#ifdef EMFILE
845			    || save_errno == EMFILE
846#endif /* EMFILE */
847#ifdef ENFILE
848			    || save_errno == ENFILE
849#endif /* ENFILE */
850#ifdef ENOBUFS
851			    || save_errno == ENOBUFS
852#endif /* ENOBUFS */
853#ifdef ENOMEM
854			    || save_errno == ENOMEM
855#endif /* ENOMEM */
856#ifdef ENOSR
857			    || save_errno == ENOSR
858#endif /* ENOSR */
859#ifdef EWOULDBLOCK
860			    || save_errno == EWOULDBLOCK
861#endif /* EWOULDBLOCK */
862			   )
863				continue;
864			acnt++;
865			smi_log(SMI_LOG_ERR,
866				"%s: accept() returned invalid socket (%s), %s",
867				smfi->xxfi_name, sm_errstring(save_errno),
868				acnt >= MAX_FAILS_A ? "abort" : "try again");
869			MI_SLEEP(acnt);
870			if (acnt >= MAX_FAILS_A)
871			{
872				ret = MI_FAILURE;
873				break;
874			}
875			continue;
876		}
877		acnt = 0;	/* reset error counter for accept() */
878#if _FFR_DUP_FD
879		dupfd = fcntl(connfd, F_DUPFD, 256);
880		if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd))
881		{
882			close(connfd);
883			connfd = dupfd;
884			dupfd = INVALID_SOCKET;
885		}
886#endif /* _FFR_DUP_FD */
887
888		if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
889				(void *) &sockopt, sizeof sockopt) < 0)
890		{
891			smi_log(SMI_LOG_WARN,
892				"%s: set keepalive failed (%s)",
893				smfi->xxfi_name, sm_errstring(errno));
894			/* XXX: continue? */
895		}
896		if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
897		{
898			(void) closesocket(connfd);
899			mcnt++;
900			smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
901				smfi->xxfi_name, sm_errstring(save_errno),
902				mcnt >= MAX_FAILS_M ? "abort" : "try again");
903			MI_SLEEP(mcnt);
904			if (mcnt >= MAX_FAILS_M)
905			{
906				ret = MI_FAILURE;
907				break;
908			}
909			continue;
910		}
911		mcnt = 0;	/* reset error counter for malloc() */
912		(void) memset(ctx, '\0', sizeof *ctx);
913		ctx->ctx_sd = connfd;
914		ctx->ctx_dbg = dbg;
915		ctx->ctx_timeout = timeout;
916		ctx->ctx_smfi = smfi;
917		if (smfi->xxfi_connect == NULL)
918			ctx->ctx_pflags |= SMFIP_NOCONNECT;
919		if (smfi->xxfi_helo == NULL)
920			ctx->ctx_pflags |= SMFIP_NOHELO;
921		if (smfi->xxfi_envfrom == NULL)
922			ctx->ctx_pflags |= SMFIP_NOMAIL;
923		if (smfi->xxfi_envrcpt == NULL)
924			ctx->ctx_pflags |= SMFIP_NORCPT;
925		if (smfi->xxfi_header == NULL)
926			ctx->ctx_pflags |= SMFIP_NOHDRS;
927		if (smfi->xxfi_eoh == NULL)
928			ctx->ctx_pflags |= SMFIP_NOEOH;
929		if (smfi->xxfi_body == NULL)
930			ctx->ctx_pflags |= SMFIP_NOBODY;
931		if (smfi->xxfi_version <= 3 || smfi->xxfi_data == NULL)
932			ctx->ctx_pflags |= SMFIP_NODATA;
933		if (smfi->xxfi_version <= 2 || smfi->xxfi_unknown == NULL)
934			ctx->ctx_pflags |= SMFIP_NOUNKNOWN;
935
936#if _FFR_WORKERS_POOL
937# define LOG_CRT_FAIL	"%s: mi_start_session() failed: %d, %s"
938		if ((r = mi_start_session(ctx)) != MI_SUCCESS)
939#else /* _FFR_WORKERS_POOL */
940# define LOG_CRT_FAIL	"%s: thread_create() failed: %d, %s"
941		if ((r = thread_create(&thread_id,
942					mi_thread_handle_wrapper,
943					(void *) ctx)) != 0)
944#endif /* _FFR_WORKERS_POOL */
945		{
946			tcnt++;
947			smi_log(SMI_LOG_ERR,
948				LOG_CRT_FAIL,
949				smfi->xxfi_name,  r,
950				tcnt >= MAX_FAILS_T ? "abort" : "try again");
951			MI_SLEEP(tcnt);
952			(void) closesocket(connfd);
953			free(ctx);
954			if (tcnt >= MAX_FAILS_T)
955			{
956				ret = MI_FAILURE;
957				break;
958			}
959			continue;
960		}
961		tcnt = 0;
962	}
963	if (ret != MI_SUCCESS)
964		mi_stop_milters(MILTER_ABRT);
965	else
966	{
967		if (mistop != MILTER_CONT)
968			smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
969				smfi->xxfi_name, mistop);
970		mi_closener();
971	}
972	(void) smutex_destroy(&L_Mutex);
973	return ret;
974}
975