xref: /illumos-gate/usr/src/cmd/sendmail/libmilter/listener.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  *  Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
6*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
7*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  */
10*7c478bd9Sstevel@tonic-gate 
11*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
12*7c478bd9Sstevel@tonic-gate 
13*7c478bd9Sstevel@tonic-gate #include <sm/gen.h>
14*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: listener.c,v 8.111 2004/09/20 21:11:15 msk Exp $")
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate /*
17*7c478bd9Sstevel@tonic-gate **  listener.c -- threaded network listener
18*7c478bd9Sstevel@tonic-gate */
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate #include "libmilter.h"
21*7c478bd9Sstevel@tonic-gate #include <sm/errstring.h>
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
24*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
28*7c478bd9Sstevel@tonic-gate #  include <arpa/inet.h>
29*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate static smutex_t L_Mutex;
32*7c478bd9Sstevel@tonic-gate static int L_family;
33*7c478bd9Sstevel@tonic-gate static SOCKADDR_LEN_T L_socksize;
34*7c478bd9Sstevel@tonic-gate static socket_t listenfd = INVALID_SOCKET;
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate static socket_t mi_milteropen __P((char *, int, bool, char *));
37*7c478bd9Sstevel@tonic-gate static void *mi_thread_handle_wrapper __P((void *));
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate /*
40*7c478bd9Sstevel@tonic-gate **  MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
41*7c478bd9Sstevel@tonic-gate **
42*7c478bd9Sstevel@tonic-gate **	Parameters:
43*7c478bd9Sstevel@tonic-gate **		conn -- connection description
44*7c478bd9Sstevel@tonic-gate **		backlog -- listen backlog
45*7c478bd9Sstevel@tonic-gate **		dbg -- debug level
46*7c478bd9Sstevel@tonic-gate **		rmsocket -- if true, try to unlink() the socket first
47*7c478bd9Sstevel@tonic-gate **			(UNIX domain sockets only)
48*7c478bd9Sstevel@tonic-gate **		smfi -- filter structure to use
49*7c478bd9Sstevel@tonic-gate **
50*7c478bd9Sstevel@tonic-gate **	Return value:
51*7c478bd9Sstevel@tonic-gate **		MI_SUCCESS/MI_FAILURE
52*7c478bd9Sstevel@tonic-gate */
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate int
55*7c478bd9Sstevel@tonic-gate mi_opensocket(conn, backlog, dbg, rmsocket, smfi)
56*7c478bd9Sstevel@tonic-gate 	char *conn;
57*7c478bd9Sstevel@tonic-gate 	int backlog;
58*7c478bd9Sstevel@tonic-gate 	int dbg;
59*7c478bd9Sstevel@tonic-gate 	bool rmsocket;
60*7c478bd9Sstevel@tonic-gate 	smfiDesc_ptr smfi;
61*7c478bd9Sstevel@tonic-gate {
62*7c478bd9Sstevel@tonic-gate 	if (smfi == NULL || conn == NULL)
63*7c478bd9Sstevel@tonic-gate 		return MI_FAILURE;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate 	if (ValidSocket(listenfd))
66*7c478bd9Sstevel@tonic-gate 		return MI_SUCCESS;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	if (dbg > 0)
69*7c478bd9Sstevel@tonic-gate 	{
70*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_DEBUG,
71*7c478bd9Sstevel@tonic-gate 			"%s: Opening listen socket on conn %s",
72*7c478bd9Sstevel@tonic-gate 			smfi->xxfi_name, conn);
73*7c478bd9Sstevel@tonic-gate 	}
74*7c478bd9Sstevel@tonic-gate 	(void) smutex_init(&L_Mutex);
75*7c478bd9Sstevel@tonic-gate 	(void) smutex_lock(&L_Mutex);
76*7c478bd9Sstevel@tonic-gate 	listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name);
77*7c478bd9Sstevel@tonic-gate 	if (!ValidSocket(listenfd))
78*7c478bd9Sstevel@tonic-gate 	{
79*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_FATAL,
80*7c478bd9Sstevel@tonic-gate 			"%s: Unable to create listening socket on conn %s",
81*7c478bd9Sstevel@tonic-gate 			smfi->xxfi_name, conn);
82*7c478bd9Sstevel@tonic-gate 		(void) smutex_unlock(&L_Mutex);
83*7c478bd9Sstevel@tonic-gate 		return MI_FAILURE;
84*7c478bd9Sstevel@tonic-gate 	}
85*7c478bd9Sstevel@tonic-gate #if !SM_CONF_POLL
86*7c478bd9Sstevel@tonic-gate 	if (!SM_FD_OK_SELECT(listenfd))
87*7c478bd9Sstevel@tonic-gate 	{
88*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
89*7c478bd9Sstevel@tonic-gate 			smfi->xxfi_name, listenfd, FD_SETSIZE);
90*7c478bd9Sstevel@tonic-gate 		(void) smutex_unlock(&L_Mutex);
91*7c478bd9Sstevel@tonic-gate 		return MI_FAILURE;
92*7c478bd9Sstevel@tonic-gate 	}
93*7c478bd9Sstevel@tonic-gate #endif /* !SM_CONF_POLL */
94*7c478bd9Sstevel@tonic-gate 	(void) smutex_unlock(&L_Mutex);
95*7c478bd9Sstevel@tonic-gate 	return MI_SUCCESS;
96*7c478bd9Sstevel@tonic-gate }
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /*
99*7c478bd9Sstevel@tonic-gate **  MI_MILTEROPEN -- setup socket to listen on
100*7c478bd9Sstevel@tonic-gate **
101*7c478bd9Sstevel@tonic-gate **	Parameters:
102*7c478bd9Sstevel@tonic-gate **		conn -- connection description
103*7c478bd9Sstevel@tonic-gate **		backlog -- listen backlog
104*7c478bd9Sstevel@tonic-gate **		rmsocket -- if true, try to unlink() the socket first
105*7c478bd9Sstevel@tonic-gate **			(UNIX domain sockets only)
106*7c478bd9Sstevel@tonic-gate **		name -- name for logging
107*7c478bd9Sstevel@tonic-gate **
108*7c478bd9Sstevel@tonic-gate **	Returns:
109*7c478bd9Sstevel@tonic-gate **		socket upon success, error code otherwise.
110*7c478bd9Sstevel@tonic-gate **
111*7c478bd9Sstevel@tonic-gate **	Side effect:
112*7c478bd9Sstevel@tonic-gate **		sets sockpath if UNIX socket.
113*7c478bd9Sstevel@tonic-gate */
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate #if NETUNIX
116*7c478bd9Sstevel@tonic-gate static char	*sockpath = NULL;
117*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate static socket_t
120*7c478bd9Sstevel@tonic-gate mi_milteropen(conn, backlog, rmsocket, name)
121*7c478bd9Sstevel@tonic-gate 	char *conn;
122*7c478bd9Sstevel@tonic-gate 	int backlog;
123*7c478bd9Sstevel@tonic-gate 	bool rmsocket;
124*7c478bd9Sstevel@tonic-gate 	char *name;
125*7c478bd9Sstevel@tonic-gate {
126*7c478bd9Sstevel@tonic-gate 	socket_t sock;
127*7c478bd9Sstevel@tonic-gate 	int sockopt = 1;
128*7c478bd9Sstevel@tonic-gate 	int fdflags;
129*7c478bd9Sstevel@tonic-gate 	size_t len = 0;
130*7c478bd9Sstevel@tonic-gate 	char *p;
131*7c478bd9Sstevel@tonic-gate 	char *colon;
132*7c478bd9Sstevel@tonic-gate 	char *at;
133*7c478bd9Sstevel@tonic-gate 	SOCKADDR addr;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	if (conn == NULL || conn[0] == '\0')
136*7c478bd9Sstevel@tonic-gate 	{
137*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
138*7c478bd9Sstevel@tonic-gate 			name);
139*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 	(void) memset(&addr, '\0', sizeof addr);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/* protocol:filename or protocol:port@host */
144*7c478bd9Sstevel@tonic-gate 	p = conn;
145*7c478bd9Sstevel@tonic-gate 	colon = strchr(p, ':');
146*7c478bd9Sstevel@tonic-gate 	if (colon != NULL)
147*7c478bd9Sstevel@tonic-gate 	{
148*7c478bd9Sstevel@tonic-gate 		*colon = '\0';
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 		if (*p == '\0')
151*7c478bd9Sstevel@tonic-gate 		{
152*7c478bd9Sstevel@tonic-gate #if NETUNIX
153*7c478bd9Sstevel@tonic-gate 			/* default to AF_UNIX */
154*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_UNIX;
155*7c478bd9Sstevel@tonic-gate 			L_socksize = sizeof (struct sockaddr_un);
156*7c478bd9Sstevel@tonic-gate #else /* NETUNIX */
157*7c478bd9Sstevel@tonic-gate # if NETINET
158*7c478bd9Sstevel@tonic-gate 			/* default to AF_INET */
159*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET;
160*7c478bd9Sstevel@tonic-gate 			L_socksize = sizeof addr.sin;
161*7c478bd9Sstevel@tonic-gate # else /* NETINET */
162*7c478bd9Sstevel@tonic-gate #  if NETINET6
163*7c478bd9Sstevel@tonic-gate 			/* default to AF_INET6 */
164*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET6;
165*7c478bd9Sstevel@tonic-gate 			L_socksize = sizeof addr.sin6;
166*7c478bd9Sstevel@tonic-gate #  else /* NETINET6 */
167*7c478bd9Sstevel@tonic-gate 			/* no protocols available */
168*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
169*7c478bd9Sstevel@tonic-gate 				"%s: no valid socket protocols available",
170*7c478bd9Sstevel@tonic-gate 				name);
171*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
172*7c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
173*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
174*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
175*7c478bd9Sstevel@tonic-gate 		}
176*7c478bd9Sstevel@tonic-gate #if NETUNIX
177*7c478bd9Sstevel@tonic-gate 		else if (strcasecmp(p, "unix") == 0 ||
178*7c478bd9Sstevel@tonic-gate 			 strcasecmp(p, "local") == 0)
179*7c478bd9Sstevel@tonic-gate 		{
180*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_UNIX;
181*7c478bd9Sstevel@tonic-gate 			L_socksize = sizeof (struct sockaddr_un);
182*7c478bd9Sstevel@tonic-gate 		}
183*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
184*7c478bd9Sstevel@tonic-gate #if NETINET
185*7c478bd9Sstevel@tonic-gate 		else if (strcasecmp(p, "inet") == 0)
186*7c478bd9Sstevel@tonic-gate 		{
187*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET;
188*7c478bd9Sstevel@tonic-gate 			L_socksize = sizeof addr.sin;
189*7c478bd9Sstevel@tonic-gate 		}
190*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
191*7c478bd9Sstevel@tonic-gate #if NETINET6
192*7c478bd9Sstevel@tonic-gate 		else if (strcasecmp(p, "inet6") == 0)
193*7c478bd9Sstevel@tonic-gate 		{
194*7c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET6;
195*7c478bd9Sstevel@tonic-gate 			L_socksize = sizeof addr.sin6;
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
198*7c478bd9Sstevel@tonic-gate 		else
199*7c478bd9Sstevel@tonic-gate 		{
200*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
201*7c478bd9Sstevel@tonic-gate 				name, p);
202*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
203*7c478bd9Sstevel@tonic-gate 		}
204*7c478bd9Sstevel@tonic-gate 		*colon++ = ':';
205*7c478bd9Sstevel@tonic-gate 	}
206*7c478bd9Sstevel@tonic-gate 	else
207*7c478bd9Sstevel@tonic-gate 	{
208*7c478bd9Sstevel@tonic-gate 		colon = p;
209*7c478bd9Sstevel@tonic-gate #if NETUNIX
210*7c478bd9Sstevel@tonic-gate 		/* default to AF_UNIX */
211*7c478bd9Sstevel@tonic-gate 		addr.sa.sa_family = AF_UNIX;
212*7c478bd9Sstevel@tonic-gate 		L_socksize = sizeof (struct sockaddr_un);
213*7c478bd9Sstevel@tonic-gate #else /* NETUNIX */
214*7c478bd9Sstevel@tonic-gate # if NETINET
215*7c478bd9Sstevel@tonic-gate 		/* default to AF_INET */
216*7c478bd9Sstevel@tonic-gate 		addr.sa.sa_family = AF_INET;
217*7c478bd9Sstevel@tonic-gate 		L_socksize = sizeof addr.sin;
218*7c478bd9Sstevel@tonic-gate # else /* NETINET */
219*7c478bd9Sstevel@tonic-gate #  if NETINET6
220*7c478bd9Sstevel@tonic-gate 		/* default to AF_INET6 */
221*7c478bd9Sstevel@tonic-gate 		addr.sa.sa_family = AF_INET6;
222*7c478bd9Sstevel@tonic-gate 		L_socksize = sizeof addr.sin6;
223*7c478bd9Sstevel@tonic-gate #  else /* NETINET6 */
224*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
225*7c478bd9Sstevel@tonic-gate 			name, p);
226*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
227*7c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
228*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
229*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate #if NETUNIX
233*7c478bd9Sstevel@tonic-gate 	if (addr.sa.sa_family == AF_UNIX)
234*7c478bd9Sstevel@tonic-gate 	{
235*7c478bd9Sstevel@tonic-gate # if 0
236*7c478bd9Sstevel@tonic-gate 		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
237*7c478bd9Sstevel@tonic-gate # endif /* 0 */
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 		at = colon;
240*7c478bd9Sstevel@tonic-gate 		len = strlen(colon) + 1;
241*7c478bd9Sstevel@tonic-gate 		if (len >= sizeof addr.sunix.sun_path)
242*7c478bd9Sstevel@tonic-gate 		{
243*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
244*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
245*7c478bd9Sstevel@tonic-gate 				name, colon);
246*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(addr.sunix.sun_path, colon,
249*7c478bd9Sstevel@tonic-gate 				sizeof addr.sunix.sun_path);
250*7c478bd9Sstevel@tonic-gate # if 0
251*7c478bd9Sstevel@tonic-gate 		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
252*7c478bd9Sstevel@tonic-gate 				 S_IRUSR|S_IWUSR, NULL);
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 		/* if not safe, don't create */
255*7c478bd9Sstevel@tonic-gate 		if (errno != 0)
256*7c478bd9Sstevel@tonic-gate 		{
257*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
258*7c478bd9Sstevel@tonic-gate 				"%s: UNIX socket name %s unsafe",
259*7c478bd9Sstevel@tonic-gate 				name, colon);
260*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
261*7c478bd9Sstevel@tonic-gate 		}
262*7c478bd9Sstevel@tonic-gate # endif /* 0 */
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
267*7c478bd9Sstevel@tonic-gate 	if (
268*7c478bd9Sstevel@tonic-gate # if NETINET
269*7c478bd9Sstevel@tonic-gate 	    addr.sa.sa_family == AF_INET
270*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
271*7c478bd9Sstevel@tonic-gate # if NETINET && NETINET6
272*7c478bd9Sstevel@tonic-gate 	    ||
273*7c478bd9Sstevel@tonic-gate # endif /* NETINET && NETINET6 */
274*7c478bd9Sstevel@tonic-gate # if NETINET6
275*7c478bd9Sstevel@tonic-gate 	    addr.sa.sa_family == AF_INET6
276*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
277*7c478bd9Sstevel@tonic-gate 	   )
278*7c478bd9Sstevel@tonic-gate 	{
279*7c478bd9Sstevel@tonic-gate 		unsigned short port;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 		/* Parse port@host */
282*7c478bd9Sstevel@tonic-gate 		at = strchr(colon, '@');
283*7c478bd9Sstevel@tonic-gate 		if (at == NULL)
284*7c478bd9Sstevel@tonic-gate 		{
285*7c478bd9Sstevel@tonic-gate 			switch (addr.sa.sa_family)
286*7c478bd9Sstevel@tonic-gate 			{
287*7c478bd9Sstevel@tonic-gate # if NETINET
288*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
289*7c478bd9Sstevel@tonic-gate 				addr.sin.sin_addr.s_addr = INADDR_ANY;
290*7c478bd9Sstevel@tonic-gate 				break;
291*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate # if NETINET6
294*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
295*7c478bd9Sstevel@tonic-gate 				addr.sin6.sin6_addr = in6addr_any;
296*7c478bd9Sstevel@tonic-gate 				break;
297*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
298*7c478bd9Sstevel@tonic-gate 			}
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 		else
301*7c478bd9Sstevel@tonic-gate 			*at = '\0';
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		if (isascii(*colon) && isdigit(*colon))
304*7c478bd9Sstevel@tonic-gate 			port = htons((unsigned short) atoi(colon));
305*7c478bd9Sstevel@tonic-gate 		else
306*7c478bd9Sstevel@tonic-gate 		{
307*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
308*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
309*7c478bd9Sstevel@tonic-gate 				name, colon);
310*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
311*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
312*7c478bd9Sstevel@tonic-gate 			register struct servent *sp;
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 			sp = getservbyname(colon, "tcp");
315*7c478bd9Sstevel@tonic-gate 			if (sp == NULL)
316*7c478bd9Sstevel@tonic-gate 			{
317*7c478bd9Sstevel@tonic-gate 				smi_log(SMI_LOG_ERR,
318*7c478bd9Sstevel@tonic-gate 					"%s: unknown port name %s",
319*7c478bd9Sstevel@tonic-gate 					name, colon);
320*7c478bd9Sstevel@tonic-gate 				return INVALID_SOCKET;
321*7c478bd9Sstevel@tonic-gate 			}
322*7c478bd9Sstevel@tonic-gate 			port = sp->s_port;
323*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 		if (at != NULL)
326*7c478bd9Sstevel@tonic-gate 		{
327*7c478bd9Sstevel@tonic-gate 			*at++ = '@';
328*7c478bd9Sstevel@tonic-gate 			if (*at == '[')
329*7c478bd9Sstevel@tonic-gate 			{
330*7c478bd9Sstevel@tonic-gate 				char *end;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 				end = strchr(at, ']');
333*7c478bd9Sstevel@tonic-gate 				if (end != NULL)
334*7c478bd9Sstevel@tonic-gate 				{
335*7c478bd9Sstevel@tonic-gate 					bool found = false;
336*7c478bd9Sstevel@tonic-gate # if NETINET
337*7c478bd9Sstevel@tonic-gate 					unsigned long hid = INADDR_NONE;
338*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
339*7c478bd9Sstevel@tonic-gate # if NETINET6
340*7c478bd9Sstevel@tonic-gate 					struct sockaddr_in6 hid6;
341*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 					*end = '\0';
344*7c478bd9Sstevel@tonic-gate # if NETINET
345*7c478bd9Sstevel@tonic-gate 					if (addr.sa.sa_family == AF_INET &&
346*7c478bd9Sstevel@tonic-gate 					    (hid = inet_addr(&at[1])) != INADDR_NONE)
347*7c478bd9Sstevel@tonic-gate 					{
348*7c478bd9Sstevel@tonic-gate 						addr.sin.sin_addr.s_addr = hid;
349*7c478bd9Sstevel@tonic-gate 						addr.sin.sin_port = port;
350*7c478bd9Sstevel@tonic-gate 						found = true;
351*7c478bd9Sstevel@tonic-gate 					}
352*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
353*7c478bd9Sstevel@tonic-gate # if NETINET6
354*7c478bd9Sstevel@tonic-gate 					(void) memset(&hid6, '\0', sizeof hid6);
355*7c478bd9Sstevel@tonic-gate 					if (addr.sa.sa_family == AF_INET6 &&
356*7c478bd9Sstevel@tonic-gate 					    mi_inet_pton(AF_INET6, &at[1],
357*7c478bd9Sstevel@tonic-gate 							 &hid6.sin6_addr) == 1)
358*7c478bd9Sstevel@tonic-gate 					{
359*7c478bd9Sstevel@tonic-gate 						addr.sin6.sin6_addr = hid6.sin6_addr;
360*7c478bd9Sstevel@tonic-gate 						addr.sin6.sin6_port = port;
361*7c478bd9Sstevel@tonic-gate 						found = true;
362*7c478bd9Sstevel@tonic-gate 					}
363*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
364*7c478bd9Sstevel@tonic-gate 					*end = ']';
365*7c478bd9Sstevel@tonic-gate 					if (!found)
366*7c478bd9Sstevel@tonic-gate 					{
367*7c478bd9Sstevel@tonic-gate 						smi_log(SMI_LOG_ERR,
368*7c478bd9Sstevel@tonic-gate 							"%s: Invalid numeric domain spec \"%s\"",
369*7c478bd9Sstevel@tonic-gate 							name, at);
370*7c478bd9Sstevel@tonic-gate 						return INVALID_SOCKET;
371*7c478bd9Sstevel@tonic-gate 					}
372*7c478bd9Sstevel@tonic-gate 				}
373*7c478bd9Sstevel@tonic-gate 				else
374*7c478bd9Sstevel@tonic-gate 				{
375*7c478bd9Sstevel@tonic-gate 					smi_log(SMI_LOG_ERR,
376*7c478bd9Sstevel@tonic-gate 						"%s: Invalid numeric domain spec \"%s\"",
377*7c478bd9Sstevel@tonic-gate 						name, at);
378*7c478bd9Sstevel@tonic-gate 					return INVALID_SOCKET;
379*7c478bd9Sstevel@tonic-gate 				}
380*7c478bd9Sstevel@tonic-gate 			}
381*7c478bd9Sstevel@tonic-gate 			else
382*7c478bd9Sstevel@tonic-gate 			{
383*7c478bd9Sstevel@tonic-gate 				struct hostent *hp = NULL;
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 				hp = mi_gethostbyname(at, addr.sa.sa_family);
386*7c478bd9Sstevel@tonic-gate 				if (hp == NULL)
387*7c478bd9Sstevel@tonic-gate 				{
388*7c478bd9Sstevel@tonic-gate 					smi_log(SMI_LOG_ERR,
389*7c478bd9Sstevel@tonic-gate 						"%s: Unknown host name %s",
390*7c478bd9Sstevel@tonic-gate 						name, at);
391*7c478bd9Sstevel@tonic-gate 					return INVALID_SOCKET;
392*7c478bd9Sstevel@tonic-gate 				}
393*7c478bd9Sstevel@tonic-gate 				addr.sa.sa_family = hp->h_addrtype;
394*7c478bd9Sstevel@tonic-gate 				switch (hp->h_addrtype)
395*7c478bd9Sstevel@tonic-gate 				{
396*7c478bd9Sstevel@tonic-gate # if NETINET
397*7c478bd9Sstevel@tonic-gate 				  case AF_INET:
398*7c478bd9Sstevel@tonic-gate 					(void) memmove(&addr.sin.sin_addr,
399*7c478bd9Sstevel@tonic-gate 						       hp->h_addr,
400*7c478bd9Sstevel@tonic-gate 						       INADDRSZ);
401*7c478bd9Sstevel@tonic-gate 					addr.sin.sin_port = port;
402*7c478bd9Sstevel@tonic-gate 					break;
403*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate # if NETINET6
406*7c478bd9Sstevel@tonic-gate 				  case AF_INET6:
407*7c478bd9Sstevel@tonic-gate 					(void) memmove(&addr.sin6.sin6_addr,
408*7c478bd9Sstevel@tonic-gate 						       hp->h_addr,
409*7c478bd9Sstevel@tonic-gate 						       IN6ADDRSZ);
410*7c478bd9Sstevel@tonic-gate 					addr.sin6.sin6_port = port;
411*7c478bd9Sstevel@tonic-gate 					break;
412*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 				  default:
415*7c478bd9Sstevel@tonic-gate 					smi_log(SMI_LOG_ERR,
416*7c478bd9Sstevel@tonic-gate 						"%s: Unknown protocol for %s (%d)",
417*7c478bd9Sstevel@tonic-gate 						name, at, hp->h_addrtype);
418*7c478bd9Sstevel@tonic-gate 					return INVALID_SOCKET;
419*7c478bd9Sstevel@tonic-gate 				}
420*7c478bd9Sstevel@tonic-gate # if NETINET6
421*7c478bd9Sstevel@tonic-gate 				freehostent(hp);
422*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
423*7c478bd9Sstevel@tonic-gate 			}
424*7c478bd9Sstevel@tonic-gate 		}
425*7c478bd9Sstevel@tonic-gate 		else
426*7c478bd9Sstevel@tonic-gate 		{
427*7c478bd9Sstevel@tonic-gate 			switch (addr.sa.sa_family)
428*7c478bd9Sstevel@tonic-gate 			{
429*7c478bd9Sstevel@tonic-gate # if NETINET
430*7c478bd9Sstevel@tonic-gate 			  case AF_INET:
431*7c478bd9Sstevel@tonic-gate 				addr.sin.sin_port = port;
432*7c478bd9Sstevel@tonic-gate 				break;
433*7c478bd9Sstevel@tonic-gate # endif /* NETINET */
434*7c478bd9Sstevel@tonic-gate # if NETINET6
435*7c478bd9Sstevel@tonic-gate 			  case AF_INET6:
436*7c478bd9Sstevel@tonic-gate 				addr.sin6.sin6_port = port;
437*7c478bd9Sstevel@tonic-gate 				break;
438*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
439*7c478bd9Sstevel@tonic-gate 			}
440*7c478bd9Sstevel@tonic-gate 		}
441*7c478bd9Sstevel@tonic-gate 	}
442*7c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
445*7c478bd9Sstevel@tonic-gate 	if (!ValidSocket(sock))
446*7c478bd9Sstevel@tonic-gate 	{
447*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
448*7c478bd9Sstevel@tonic-gate 			"%s: Unable to create new socket: %s",
449*7c478bd9Sstevel@tonic-gate 			name, sm_errstring(errno));
450*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
454*7c478bd9Sstevel@tonic-gate 	    fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
455*7c478bd9Sstevel@tonic-gate 	{
456*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
457*7c478bd9Sstevel@tonic-gate 			"%s: Unable to set close-on-exec: %s", name,
458*7c478bd9Sstevel@tonic-gate 			sm_errstring(errno));
459*7c478bd9Sstevel@tonic-gate 		(void) closesocket(sock);
460*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
464*7c478bd9Sstevel@tonic-gate 		       sizeof(sockopt)) == -1)
465*7c478bd9Sstevel@tonic-gate 	{
466*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
467*7c478bd9Sstevel@tonic-gate 			"%s: Unable to setsockopt: %s", name,
468*7c478bd9Sstevel@tonic-gate 			sm_errstring(errno));
469*7c478bd9Sstevel@tonic-gate 		(void) closesocket(sock);
470*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate #if NETUNIX
474*7c478bd9Sstevel@tonic-gate 	if (addr.sa.sa_family == AF_UNIX && rmsocket)
475*7c478bd9Sstevel@tonic-gate 	{
476*7c478bd9Sstevel@tonic-gate 		struct stat s;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 		if (stat(colon, &s) != 0)
479*7c478bd9Sstevel@tonic-gate 		{
480*7c478bd9Sstevel@tonic-gate 			if (errno != ENOENT)
481*7c478bd9Sstevel@tonic-gate 			{
482*7c478bd9Sstevel@tonic-gate 				smi_log(SMI_LOG_ERR,
483*7c478bd9Sstevel@tonic-gate 					"%s: Unable to stat() %s: %s",
484*7c478bd9Sstevel@tonic-gate 					name, colon, sm_errstring(errno));
485*7c478bd9Sstevel@tonic-gate 				(void) closesocket(sock);
486*7c478bd9Sstevel@tonic-gate 				return INVALID_SOCKET;
487*7c478bd9Sstevel@tonic-gate 			}
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 		else if (!S_ISSOCK(s.st_mode))
490*7c478bd9Sstevel@tonic-gate 		{
491*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
492*7c478bd9Sstevel@tonic-gate 				"%s: %s is not a UNIX domain socket",
493*7c478bd9Sstevel@tonic-gate 				name, colon);
494*7c478bd9Sstevel@tonic-gate 			(void) closesocket(sock);
495*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
496*7c478bd9Sstevel@tonic-gate 		}
497*7c478bd9Sstevel@tonic-gate 		else if (unlink(colon) != 0)
498*7c478bd9Sstevel@tonic-gate 		{
499*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
500*7c478bd9Sstevel@tonic-gate 				"%s: Unable to remove %s: %s",
501*7c478bd9Sstevel@tonic-gate 				name, colon, sm_errstring(errno));
502*7c478bd9Sstevel@tonic-gate 			(void) closesocket(sock);
503*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
504*7c478bd9Sstevel@tonic-gate 		}
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	if (bind(sock, &addr.sa, L_socksize) < 0)
509*7c478bd9Sstevel@tonic-gate 	{
510*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
511*7c478bd9Sstevel@tonic-gate 			"%s: Unable to bind to port %s: %s",
512*7c478bd9Sstevel@tonic-gate 			name, conn, sm_errstring(errno));
513*7c478bd9Sstevel@tonic-gate 		(void) closesocket(sock);
514*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
515*7c478bd9Sstevel@tonic-gate 	}
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	if (listen(sock, backlog) < 0)
518*7c478bd9Sstevel@tonic-gate 	{
519*7c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
520*7c478bd9Sstevel@tonic-gate 			"%s: listen call failed: %s", name,
521*7c478bd9Sstevel@tonic-gate 			sm_errstring(errno));
522*7c478bd9Sstevel@tonic-gate 		(void) closesocket(sock);
523*7c478bd9Sstevel@tonic-gate 		return INVALID_SOCKET;
524*7c478bd9Sstevel@tonic-gate 	}
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate #if NETUNIX
527*7c478bd9Sstevel@tonic-gate 	if (addr.sa.sa_family == AF_UNIX && len > 0)
528*7c478bd9Sstevel@tonic-gate 	{
529*7c478bd9Sstevel@tonic-gate 		/*
530*7c478bd9Sstevel@tonic-gate 		**  Set global variable sockpath so the UNIX socket can be
531*7c478bd9Sstevel@tonic-gate 		**  unlink()ed at exit.
532*7c478bd9Sstevel@tonic-gate 		*/
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 		sockpath = (char *) malloc(len);
535*7c478bd9Sstevel@tonic-gate 		if (sockpath != NULL)
536*7c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(sockpath, colon, len);
537*7c478bd9Sstevel@tonic-gate 		else
538*7c478bd9Sstevel@tonic-gate 		{
539*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
540*7c478bd9Sstevel@tonic-gate 				"%s: can't malloc(%d) for sockpath: %s",
541*7c478bd9Sstevel@tonic-gate 				name, (int) len, sm_errstring(errno));
542*7c478bd9Sstevel@tonic-gate 			(void) closesocket(sock);
543*7c478bd9Sstevel@tonic-gate 			return INVALID_SOCKET;
544*7c478bd9Sstevel@tonic-gate 		}
545*7c478bd9Sstevel@tonic-gate 	}
546*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
547*7c478bd9Sstevel@tonic-gate 	L_family = addr.sa.sa_family;
548*7c478bd9Sstevel@tonic-gate 	return sock;
549*7c478bd9Sstevel@tonic-gate }
550*7c478bd9Sstevel@tonic-gate /*
551*7c478bd9Sstevel@tonic-gate **  MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
552*7c478bd9Sstevel@tonic-gate **
553*7c478bd9Sstevel@tonic-gate **	Parameters:
554*7c478bd9Sstevel@tonic-gate **		arg -- argument to pass to mi_handle_session()
555*7c478bd9Sstevel@tonic-gate **
556*7c478bd9Sstevel@tonic-gate **	Returns:
557*7c478bd9Sstevel@tonic-gate **		results from mi_handle_session()
558*7c478bd9Sstevel@tonic-gate */
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate static void *
561*7c478bd9Sstevel@tonic-gate mi_thread_handle_wrapper(arg)
562*7c478bd9Sstevel@tonic-gate 	void *arg;
563*7c478bd9Sstevel@tonic-gate {
564*7c478bd9Sstevel@tonic-gate 	return (void *) mi_handle_session(arg);
565*7c478bd9Sstevel@tonic-gate }
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate /*
568*7c478bd9Sstevel@tonic-gate **  MI_CLOSENER -- close listen socket
569*7c478bd9Sstevel@tonic-gate **
570*7c478bd9Sstevel@tonic-gate **	NOTE: It is assumed that this function is called from a
571*7c478bd9Sstevel@tonic-gate **	      function that has a mutex lock (currently mi_stop_milters()).
572*7c478bd9Sstevel@tonic-gate **
573*7c478bd9Sstevel@tonic-gate **	Parameters:
574*7c478bd9Sstevel@tonic-gate **		none.
575*7c478bd9Sstevel@tonic-gate **
576*7c478bd9Sstevel@tonic-gate **	Returns:
577*7c478bd9Sstevel@tonic-gate **		none.
578*7c478bd9Sstevel@tonic-gate */
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate void
581*7c478bd9Sstevel@tonic-gate mi_closener()
582*7c478bd9Sstevel@tonic-gate {
583*7c478bd9Sstevel@tonic-gate 	(void) smutex_lock(&L_Mutex);
584*7c478bd9Sstevel@tonic-gate 	if (ValidSocket(listenfd))
585*7c478bd9Sstevel@tonic-gate 	{
586*7c478bd9Sstevel@tonic-gate #if NETUNIX
587*7c478bd9Sstevel@tonic-gate 		bool removable;
588*7c478bd9Sstevel@tonic-gate 		struct stat sockinfo;
589*7c478bd9Sstevel@tonic-gate 		struct stat fileinfo;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 		removable = sockpath != NULL &&
592*7c478bd9Sstevel@tonic-gate 			    geteuid() != 0 &&
593*7c478bd9Sstevel@tonic-gate 			    fstat(listenfd, &sockinfo) == 0 &&
594*7c478bd9Sstevel@tonic-gate 			    (S_ISFIFO(sockinfo.st_mode)
595*7c478bd9Sstevel@tonic-gate # ifdef S_ISSOCK
596*7c478bd9Sstevel@tonic-gate 			     || S_ISSOCK(sockinfo.st_mode)
597*7c478bd9Sstevel@tonic-gate # endif /* S_ISSOCK */
598*7c478bd9Sstevel@tonic-gate 			    );
599*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 		(void) closesocket(listenfd);
602*7c478bd9Sstevel@tonic-gate 		listenfd = INVALID_SOCKET;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate #if NETUNIX
605*7c478bd9Sstevel@tonic-gate 		/* XXX sleep() some time before doing this? */
606*7c478bd9Sstevel@tonic-gate 		if (sockpath != NULL)
607*7c478bd9Sstevel@tonic-gate 		{
608*7c478bd9Sstevel@tonic-gate 			if (removable &&
609*7c478bd9Sstevel@tonic-gate 			    stat(sockpath, &fileinfo) == 0 &&
610*7c478bd9Sstevel@tonic-gate 			    ((fileinfo.st_dev == sockinfo.st_dev &&
611*7c478bd9Sstevel@tonic-gate 			      fileinfo.st_ino == sockinfo.st_ino)
612*7c478bd9Sstevel@tonic-gate # ifdef S_ISSOCK
613*7c478bd9Sstevel@tonic-gate 			     || S_ISSOCK(fileinfo.st_mode)
614*7c478bd9Sstevel@tonic-gate # endif /* S_ISSOCK */
615*7c478bd9Sstevel@tonic-gate 			    )
616*7c478bd9Sstevel@tonic-gate 			    &&
617*7c478bd9Sstevel@tonic-gate 			    (S_ISFIFO(fileinfo.st_mode)
618*7c478bd9Sstevel@tonic-gate # ifdef S_ISSOCK
619*7c478bd9Sstevel@tonic-gate 			     || S_ISSOCK(fileinfo.st_mode)
620*7c478bd9Sstevel@tonic-gate # endif /* S_ISSOCK */
621*7c478bd9Sstevel@tonic-gate 			     ))
622*7c478bd9Sstevel@tonic-gate 				(void) unlink(sockpath);
623*7c478bd9Sstevel@tonic-gate 			free(sockpath);
624*7c478bd9Sstevel@tonic-gate 			sockpath = NULL;
625*7c478bd9Sstevel@tonic-gate 		}
626*7c478bd9Sstevel@tonic-gate #endif /* NETUNIX */
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 	(void) smutex_unlock(&L_Mutex);
629*7c478bd9Sstevel@tonic-gate }
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate /*
632*7c478bd9Sstevel@tonic-gate **  MI_LISTENER -- Generic listener harness
633*7c478bd9Sstevel@tonic-gate **
634*7c478bd9Sstevel@tonic-gate **	Open up listen port
635*7c478bd9Sstevel@tonic-gate **	Wait for connections
636*7c478bd9Sstevel@tonic-gate **
637*7c478bd9Sstevel@tonic-gate **	Parameters:
638*7c478bd9Sstevel@tonic-gate **		conn -- connection description
639*7c478bd9Sstevel@tonic-gate **		dbg -- debug level
640*7c478bd9Sstevel@tonic-gate **		smfi -- filter structure to use
641*7c478bd9Sstevel@tonic-gate **		timeout -- timeout for reads/writes
642*7c478bd9Sstevel@tonic-gate **		backlog -- listen queue backlog size
643*7c478bd9Sstevel@tonic-gate **
644*7c478bd9Sstevel@tonic-gate **	Returns:
645*7c478bd9Sstevel@tonic-gate **		MI_SUCCESS -- Exited normally
646*7c478bd9Sstevel@tonic-gate **			   (session finished or we were told to exit)
647*7c478bd9Sstevel@tonic-gate **		MI_FAILURE -- Network initialization failed.
648*7c478bd9Sstevel@tonic-gate */
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate #if BROKEN_PTHREAD_SLEEP
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate /*
653*7c478bd9Sstevel@tonic-gate **  Solaris 2.6, perhaps others, gets an internal threads library panic
654*7c478bd9Sstevel@tonic-gate **  when sleep() is used:
655*7c478bd9Sstevel@tonic-gate **
656*7c478bd9Sstevel@tonic-gate **  thread_create() failed, returned 11 (EINVAL)
657*7c478bd9Sstevel@tonic-gate **  co_enable, thr_create() returned error = 24
658*7c478bd9Sstevel@tonic-gate **  libthread panic: co_enable failed (PID: 17793 LWP 1)
659*7c478bd9Sstevel@tonic-gate **  stacktrace:
660*7c478bd9Sstevel@tonic-gate **	ef526b10
661*7c478bd9Sstevel@tonic-gate **	ef52646c
662*7c478bd9Sstevel@tonic-gate **	ef534cbc
663*7c478bd9Sstevel@tonic-gate **	156a4
664*7c478bd9Sstevel@tonic-gate **	14644
665*7c478bd9Sstevel@tonic-gate **	1413c
666*7c478bd9Sstevel@tonic-gate **	135e0
667*7c478bd9Sstevel@tonic-gate **	0
668*7c478bd9Sstevel@tonic-gate */
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate # define MI_SLEEP(s)							\
671*7c478bd9Sstevel@tonic-gate {									\
672*7c478bd9Sstevel@tonic-gate 	int rs = 0;							\
673*7c478bd9Sstevel@tonic-gate 	struct timeval st;						\
674*7c478bd9Sstevel@tonic-gate 									\
675*7c478bd9Sstevel@tonic-gate 	st.tv_sec = (s);						\
676*7c478bd9Sstevel@tonic-gate 	st.tv_usec = 0;							\
677*7c478bd9Sstevel@tonic-gate 	if (st.tv_sec > 0)						\
678*7c478bd9Sstevel@tonic-gate 	{								\
679*7c478bd9Sstevel@tonic-gate 		for (;;)						\
680*7c478bd9Sstevel@tonic-gate 		{							\
681*7c478bd9Sstevel@tonic-gate 			rs = select(0, NULL, NULL, NULL, &st);		\
682*7c478bd9Sstevel@tonic-gate 			if (rs < 0 && errno == EINTR)			\
683*7c478bd9Sstevel@tonic-gate 				continue;				\
684*7c478bd9Sstevel@tonic-gate 			if (rs != 0)					\
685*7c478bd9Sstevel@tonic-gate 			{						\
686*7c478bd9Sstevel@tonic-gate 				smi_log(SMI_LOG_ERR,			\
687*7c478bd9Sstevel@tonic-gate 					"MI_SLEEP(): select() returned non-zero result %d, errno = %d",	\
688*7c478bd9Sstevel@tonic-gate 					rs, errno);			\
689*7c478bd9Sstevel@tonic-gate 			}						\
690*7c478bd9Sstevel@tonic-gate 			break;						\
691*7c478bd9Sstevel@tonic-gate 		}							\
692*7c478bd9Sstevel@tonic-gate 	}								\
693*7c478bd9Sstevel@tonic-gate }
694*7c478bd9Sstevel@tonic-gate #else /* BROKEN_PTHREAD_SLEEP */
695*7c478bd9Sstevel@tonic-gate # define MI_SLEEP(s)	sleep((s))
696*7c478bd9Sstevel@tonic-gate #endif /* BROKEN_PTHREAD_SLEEP */
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate int
699*7c478bd9Sstevel@tonic-gate mi_listener(conn, dbg, smfi, timeout, backlog)
700*7c478bd9Sstevel@tonic-gate 	char *conn;
701*7c478bd9Sstevel@tonic-gate 	int dbg;
702*7c478bd9Sstevel@tonic-gate 	smfiDesc_ptr smfi;
703*7c478bd9Sstevel@tonic-gate 	time_t timeout;
704*7c478bd9Sstevel@tonic-gate 	int backlog;
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	socket_t connfd = INVALID_SOCKET;
707*7c478bd9Sstevel@tonic-gate #if _FFR_DUP_FD
708*7c478bd9Sstevel@tonic-gate 	socket_t dupfd = INVALID_SOCKET;
709*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DUP_FD */
710*7c478bd9Sstevel@tonic-gate 	int sockopt = 1;
711*7c478bd9Sstevel@tonic-gate 	int r, mistop;
712*7c478bd9Sstevel@tonic-gate 	int ret = MI_SUCCESS;
713*7c478bd9Sstevel@tonic-gate 	int mcnt = 0;	/* error count for malloc() failures */
714*7c478bd9Sstevel@tonic-gate 	int tcnt = 0;	/* error count for thread_create() failures */
715*7c478bd9Sstevel@tonic-gate 	int acnt = 0;	/* error count for accept() failures */
716*7c478bd9Sstevel@tonic-gate 	int scnt = 0;	/* error count for select() failures */
717*7c478bd9Sstevel@tonic-gate 	int save_errno = 0;
718*7c478bd9Sstevel@tonic-gate 	sthread_t thread_id;
719*7c478bd9Sstevel@tonic-gate 	_SOCK_ADDR cliaddr;
720*7c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T clilen;
721*7c478bd9Sstevel@tonic-gate 	SMFICTX_PTR ctx;
722*7c478bd9Sstevel@tonic-gate 	FD_RD_VAR(rds, excs);
723*7c478bd9Sstevel@tonic-gate 	struct timeval chktime;
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
726*7c478bd9Sstevel@tonic-gate 		return MI_FAILURE;
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	clilen = L_socksize;
729*7c478bd9Sstevel@tonic-gate 	while ((mistop = mi_stop()) == MILTER_CONT)
730*7c478bd9Sstevel@tonic-gate 	{
731*7c478bd9Sstevel@tonic-gate 		(void) smutex_lock(&L_Mutex);
732*7c478bd9Sstevel@tonic-gate 		if (!ValidSocket(listenfd))
733*7c478bd9Sstevel@tonic-gate 		{
734*7c478bd9Sstevel@tonic-gate 			ret = MI_FAILURE;
735*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
736*7c478bd9Sstevel@tonic-gate 				"%s: listenfd=%d corrupted, terminating, errno=%d",
737*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, listenfd, errno);
738*7c478bd9Sstevel@tonic-gate 			(void) smutex_unlock(&L_Mutex);
739*7c478bd9Sstevel@tonic-gate 			break;
740*7c478bd9Sstevel@tonic-gate 		}
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 		/* select on interface ports */
743*7c478bd9Sstevel@tonic-gate 		FD_RD_INIT(listenfd, rds, excs);
744*7c478bd9Sstevel@tonic-gate 		chktime.tv_sec = MI_CHK_TIME;
745*7c478bd9Sstevel@tonic-gate 		chktime.tv_usec = 0;
746*7c478bd9Sstevel@tonic-gate 		r = FD_RD_READY(listenfd, rds, excs, &chktime);
747*7c478bd9Sstevel@tonic-gate 		if (r == 0)		/* timeout */
748*7c478bd9Sstevel@tonic-gate 		{
749*7c478bd9Sstevel@tonic-gate 			(void) smutex_unlock(&L_Mutex);
750*7c478bd9Sstevel@tonic-gate 			continue;	/* just check mi_stop() */
751*7c478bd9Sstevel@tonic-gate 		}
752*7c478bd9Sstevel@tonic-gate 		if (r < 0)
753*7c478bd9Sstevel@tonic-gate 		{
754*7c478bd9Sstevel@tonic-gate 			save_errno = errno;
755*7c478bd9Sstevel@tonic-gate 			(void) smutex_unlock(&L_Mutex);
756*7c478bd9Sstevel@tonic-gate 			if (save_errno == EINTR)
757*7c478bd9Sstevel@tonic-gate 				continue;
758*7c478bd9Sstevel@tonic-gate 			scnt++;
759*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
760*7c478bd9Sstevel@tonic-gate 				"%s: select() failed (%s), %s",
761*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, sm_errstring(save_errno),
762*7c478bd9Sstevel@tonic-gate 				scnt >= MAX_FAILS_S ? "abort" : "try again");
763*7c478bd9Sstevel@tonic-gate 			MI_SLEEP(scnt);
764*7c478bd9Sstevel@tonic-gate 			if (scnt >= MAX_FAILS_S)
765*7c478bd9Sstevel@tonic-gate 			{
766*7c478bd9Sstevel@tonic-gate 				ret = MI_FAILURE;
767*7c478bd9Sstevel@tonic-gate 				break;
768*7c478bd9Sstevel@tonic-gate 			}
769*7c478bd9Sstevel@tonic-gate 			continue;
770*7c478bd9Sstevel@tonic-gate 		}
771*7c478bd9Sstevel@tonic-gate 		if (!FD_IS_RD_RDY(listenfd, rds, excs))
772*7c478bd9Sstevel@tonic-gate 		{
773*7c478bd9Sstevel@tonic-gate 			/* some error: just stop for now... */
774*7c478bd9Sstevel@tonic-gate 			ret = MI_FAILURE;
775*7c478bd9Sstevel@tonic-gate 			(void) smutex_unlock(&L_Mutex);
776*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
777*7c478bd9Sstevel@tonic-gate 				"%s: %s() returned exception for socket, abort",
778*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, MI_POLLSELECT);
779*7c478bd9Sstevel@tonic-gate 			break;
780*7c478bd9Sstevel@tonic-gate 		}
781*7c478bd9Sstevel@tonic-gate 		scnt = 0;	/* reset error counter for select() */
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 		(void) memset(&cliaddr, '\0', sizeof cliaddr);
784*7c478bd9Sstevel@tonic-gate 		connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
785*7c478bd9Sstevel@tonic-gate 				&clilen);
786*7c478bd9Sstevel@tonic-gate 		save_errno = errno;
787*7c478bd9Sstevel@tonic-gate 		(void) smutex_unlock(&L_Mutex);
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 		/*
790*7c478bd9Sstevel@tonic-gate 		**  If remote side closes before
791*7c478bd9Sstevel@tonic-gate 		**  accept() finishes, sockaddr
792*7c478bd9Sstevel@tonic-gate 		**  might not be fully filled in.
793*7c478bd9Sstevel@tonic-gate 		*/
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 		if (ValidSocket(connfd) &&
796*7c478bd9Sstevel@tonic-gate 		    (clilen == 0 ||
797*7c478bd9Sstevel@tonic-gate # ifdef BSD4_4_SOCKADDR
798*7c478bd9Sstevel@tonic-gate 		     cliaddr.sa.sa_len == 0 ||
799*7c478bd9Sstevel@tonic-gate # endif /* BSD4_4_SOCKADDR */
800*7c478bd9Sstevel@tonic-gate 		     cliaddr.sa.sa_family != L_family))
801*7c478bd9Sstevel@tonic-gate 		{
802*7c478bd9Sstevel@tonic-gate 			(void) closesocket(connfd);
803*7c478bd9Sstevel@tonic-gate 			connfd = INVALID_SOCKET;
804*7c478bd9Sstevel@tonic-gate 			save_errno = EINVAL;
805*7c478bd9Sstevel@tonic-gate 		}
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate #if !SM_CONF_POLL
808*7c478bd9Sstevel@tonic-gate 		/* check if acceptable for select() */
809*7c478bd9Sstevel@tonic-gate 		if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
810*7c478bd9Sstevel@tonic-gate 		{
811*7c478bd9Sstevel@tonic-gate 			(void) closesocket(connfd);
812*7c478bd9Sstevel@tonic-gate 			connfd = INVALID_SOCKET;
813*7c478bd9Sstevel@tonic-gate 			save_errno = ERANGE;
814*7c478bd9Sstevel@tonic-gate 		}
815*7c478bd9Sstevel@tonic-gate #endif /* !SM_CONF_POLL */
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 		if (!ValidSocket(connfd))
818*7c478bd9Sstevel@tonic-gate 		{
819*7c478bd9Sstevel@tonic-gate 			if (save_errno == EINTR
820*7c478bd9Sstevel@tonic-gate #ifdef EAGAIN
821*7c478bd9Sstevel@tonic-gate 			    || save_errno == EAGAIN
822*7c478bd9Sstevel@tonic-gate #endif /* EAGAIN */
823*7c478bd9Sstevel@tonic-gate #ifdef ECONNABORTED
824*7c478bd9Sstevel@tonic-gate 			    || save_errno == ECONNABORTED
825*7c478bd9Sstevel@tonic-gate #endif /* ECONNABORTED */
826*7c478bd9Sstevel@tonic-gate #ifdef EMFILE
827*7c478bd9Sstevel@tonic-gate 			    || save_errno == EMFILE
828*7c478bd9Sstevel@tonic-gate #endif /* EMFILE */
829*7c478bd9Sstevel@tonic-gate #ifdef ENFILE
830*7c478bd9Sstevel@tonic-gate 			    || save_errno == ENFILE
831*7c478bd9Sstevel@tonic-gate #endif /* ENFILE */
832*7c478bd9Sstevel@tonic-gate #ifdef ENOBUFS
833*7c478bd9Sstevel@tonic-gate 			    || save_errno == ENOBUFS
834*7c478bd9Sstevel@tonic-gate #endif /* ENOBUFS */
835*7c478bd9Sstevel@tonic-gate #ifdef ENOMEM
836*7c478bd9Sstevel@tonic-gate 			    || save_errno == ENOMEM
837*7c478bd9Sstevel@tonic-gate #endif /* ENOMEM */
838*7c478bd9Sstevel@tonic-gate #ifdef ENOSR
839*7c478bd9Sstevel@tonic-gate 			    || save_errno == ENOSR
840*7c478bd9Sstevel@tonic-gate #endif /* ENOSR */
841*7c478bd9Sstevel@tonic-gate #ifdef EWOULDBLOCK
842*7c478bd9Sstevel@tonic-gate 			    || save_errno == EWOULDBLOCK
843*7c478bd9Sstevel@tonic-gate #endif /* EWOULDBLOCK */
844*7c478bd9Sstevel@tonic-gate 			   )
845*7c478bd9Sstevel@tonic-gate 				continue;
846*7c478bd9Sstevel@tonic-gate 			acnt++;
847*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
848*7c478bd9Sstevel@tonic-gate 				"%s: accept() returned invalid socket (%s), %s",
849*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, sm_errstring(save_errno),
850*7c478bd9Sstevel@tonic-gate 				acnt >= MAX_FAILS_A ? "abort" : "try again");
851*7c478bd9Sstevel@tonic-gate 			MI_SLEEP(acnt);
852*7c478bd9Sstevel@tonic-gate 			if (acnt >= MAX_FAILS_A)
853*7c478bd9Sstevel@tonic-gate 			{
854*7c478bd9Sstevel@tonic-gate 				ret = MI_FAILURE;
855*7c478bd9Sstevel@tonic-gate 				break;
856*7c478bd9Sstevel@tonic-gate 			}
857*7c478bd9Sstevel@tonic-gate 			continue;
858*7c478bd9Sstevel@tonic-gate 		}
859*7c478bd9Sstevel@tonic-gate 		acnt = 0;	/* reset error counter for accept() */
860*7c478bd9Sstevel@tonic-gate #if _FFR_DUP_FD
861*7c478bd9Sstevel@tonic-gate 		dupfd = fcntl(connfd, F_DUPFD, 256);
862*7c478bd9Sstevel@tonic-gate 		if (ValidSocket(dupfd)
863*7c478bd9Sstevel@tonic-gate # if !SM_CONF_POLL
864*7c478bd9Sstevel@tonic-gate 		    && SM_FD_OK_SELECT(dupfd)
865*7c478bd9Sstevel@tonic-gate # endif /* !SM_CONF_POLL */
866*7c478bd9Sstevel@tonic-gate 		   )
867*7c478bd9Sstevel@tonic-gate 		{
868*7c478bd9Sstevel@tonic-gate 			close(connfd);
869*7c478bd9Sstevel@tonic-gate 			connfd = dupfd;
870*7c478bd9Sstevel@tonic-gate 			dupfd = INVALID_SOCKET;
871*7c478bd9Sstevel@tonic-gate 		}
872*7c478bd9Sstevel@tonic-gate #endif /* _FFR_DUP_FD */
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 		if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
875*7c478bd9Sstevel@tonic-gate 				(void *) &sockopt, sizeof sockopt) < 0)
876*7c478bd9Sstevel@tonic-gate 		{
877*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)",
878*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, sm_errstring(errno));
879*7c478bd9Sstevel@tonic-gate 			/* XXX: continue? */
880*7c478bd9Sstevel@tonic-gate 		}
881*7c478bd9Sstevel@tonic-gate 		if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
882*7c478bd9Sstevel@tonic-gate 		{
883*7c478bd9Sstevel@tonic-gate 			(void) closesocket(connfd);
884*7c478bd9Sstevel@tonic-gate 			mcnt++;
885*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
886*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, sm_errstring(save_errno),
887*7c478bd9Sstevel@tonic-gate 				mcnt >= MAX_FAILS_M ? "abort" : "try again");
888*7c478bd9Sstevel@tonic-gate 			MI_SLEEP(mcnt);
889*7c478bd9Sstevel@tonic-gate 			if (mcnt >= MAX_FAILS_M)
890*7c478bd9Sstevel@tonic-gate 			{
891*7c478bd9Sstevel@tonic-gate 				ret = MI_FAILURE;
892*7c478bd9Sstevel@tonic-gate 				break;
893*7c478bd9Sstevel@tonic-gate 			}
894*7c478bd9Sstevel@tonic-gate 			continue;
895*7c478bd9Sstevel@tonic-gate 		}
896*7c478bd9Sstevel@tonic-gate 		mcnt = 0;	/* reset error counter for malloc() */
897*7c478bd9Sstevel@tonic-gate 		(void) memset(ctx, '\0', sizeof *ctx);
898*7c478bd9Sstevel@tonic-gate 		ctx->ctx_sd = connfd;
899*7c478bd9Sstevel@tonic-gate 		ctx->ctx_dbg = dbg;
900*7c478bd9Sstevel@tonic-gate 		ctx->ctx_timeout = timeout;
901*7c478bd9Sstevel@tonic-gate 		ctx->ctx_smfi = smfi;
902*7c478bd9Sstevel@tonic-gate #if 0
903*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_eoh == NULL)
904*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_eom == NULL)
905*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_abort == NULL)
906*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_close == NULL)
907*7c478bd9Sstevel@tonic-gate #endif /* 0 */
908*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_connect == NULL)
909*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NOCONNECT;
910*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_helo == NULL)
911*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NOHELO;
912*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_envfrom == NULL)
913*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NOMAIL;
914*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_envrcpt == NULL)
915*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NORCPT;
916*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_header == NULL)
917*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NOHDRS;
918*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_eoh == NULL)
919*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NOEOH;
920*7c478bd9Sstevel@tonic-gate 		if (smfi->xxfi_body == NULL)
921*7c478bd9Sstevel@tonic-gate 			ctx->ctx_pflags |= SMFIP_NOBODY;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 		if ((r = thread_create(&thread_id,
924*7c478bd9Sstevel@tonic-gate 					mi_thread_handle_wrapper,
925*7c478bd9Sstevel@tonic-gate 					(void *) ctx)) != 0)
926*7c478bd9Sstevel@tonic-gate 		{
927*7c478bd9Sstevel@tonic-gate 			tcnt++;
928*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
929*7c478bd9Sstevel@tonic-gate 				"%s: thread_create() failed: %d, %s",
930*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name,  r,
931*7c478bd9Sstevel@tonic-gate 				tcnt >= MAX_FAILS_T ? "abort" : "try again");
932*7c478bd9Sstevel@tonic-gate 			MI_SLEEP(tcnt);
933*7c478bd9Sstevel@tonic-gate 			(void) closesocket(connfd);
934*7c478bd9Sstevel@tonic-gate 			free(ctx);
935*7c478bd9Sstevel@tonic-gate 			if (tcnt >= MAX_FAILS_T)
936*7c478bd9Sstevel@tonic-gate 			{
937*7c478bd9Sstevel@tonic-gate 				ret = MI_FAILURE;
938*7c478bd9Sstevel@tonic-gate 				break;
939*7c478bd9Sstevel@tonic-gate 			}
940*7c478bd9Sstevel@tonic-gate 			continue;
941*7c478bd9Sstevel@tonic-gate 		}
942*7c478bd9Sstevel@tonic-gate 		tcnt = 0;
943*7c478bd9Sstevel@tonic-gate 	}
944*7c478bd9Sstevel@tonic-gate 	if (ret != MI_SUCCESS)
945*7c478bd9Sstevel@tonic-gate 		mi_stop_milters(MILTER_ABRT);
946*7c478bd9Sstevel@tonic-gate 	else
947*7c478bd9Sstevel@tonic-gate 	{
948*7c478bd9Sstevel@tonic-gate 		if (mistop != MILTER_CONT)
949*7c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
950*7c478bd9Sstevel@tonic-gate 				smfi->xxfi_name, mistop);
951*7c478bd9Sstevel@tonic-gate 		mi_closener();
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 	(void) smutex_destroy(&L_Mutex);
954*7c478bd9Sstevel@tonic-gate 	return ret;
955*7c478bd9Sstevel@tonic-gate }
956