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