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