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