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