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