Merge from vendor branch GDB:
[dragonfly.git] / contrib / sendmail-8.13.4 / libmilter / listener.c
1 /*
2  *  Copyright (c) 1999-2004 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.111 2004/09/20 21:11:15 msk 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 (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
462                        sizeof(sockopt)) == -1)
463         {
464                 smi_log(SMI_LOG_ERR,
465                         "%s: Unable to setsockopt: %s", name,
466                         sm_errstring(errno));
467                 (void) closesocket(sock);
468                 return INVALID_SOCKET;
469         }
470
471 #if NETUNIX
472         if (addr.sa.sa_family == AF_UNIX && rmsocket)
473         {
474                 struct stat s;
475
476                 if (stat(colon, &s) != 0)
477                 {
478                         if (errno != ENOENT)
479                         {
480                                 smi_log(SMI_LOG_ERR,
481                                         "%s: Unable to stat() %s: %s",
482                                         name, colon, sm_errstring(errno));
483                                 (void) closesocket(sock);
484                                 return INVALID_SOCKET;
485                         }
486                 }
487                 else if (!S_ISSOCK(s.st_mode))
488                 {
489                         smi_log(SMI_LOG_ERR,
490                                 "%s: %s is not a UNIX domain socket",
491                                 name, colon);
492                         (void) closesocket(sock);
493                         return INVALID_SOCKET;
494                 }
495                 else if (unlink(colon) != 0)
496                 {
497                         smi_log(SMI_LOG_ERR,
498                                 "%s: Unable to remove %s: %s",
499                                 name, colon, sm_errstring(errno));
500                         (void) closesocket(sock);
501                         return INVALID_SOCKET;
502                 }
503         }
504 #endif /* NETUNIX */
505
506         if (bind(sock, &addr.sa, L_socksize) < 0)
507         {
508                 smi_log(SMI_LOG_ERR,
509                         "%s: Unable to bind to port %s: %s",
510                         name, conn, sm_errstring(errno));
511                 (void) closesocket(sock);
512                 return INVALID_SOCKET;
513         }
514
515         if (listen(sock, backlog) < 0)
516         {
517                 smi_log(SMI_LOG_ERR,
518                         "%s: listen call failed: %s", name,
519                         sm_errstring(errno));
520                 (void) closesocket(sock);
521                 return INVALID_SOCKET;
522         }
523
524 #if NETUNIX
525         if (addr.sa.sa_family == AF_UNIX && len > 0)
526         {
527                 /*
528                 **  Set global variable sockpath so the UNIX socket can be
529                 **  unlink()ed at exit.
530                 */
531
532                 sockpath = (char *) malloc(len);
533                 if (sockpath != NULL)
534                         (void) sm_strlcpy(sockpath, colon, len);
535                 else
536                 {
537                         smi_log(SMI_LOG_ERR,
538                                 "%s: can't malloc(%d) for sockpath: %s",
539                                 name, (int) len, sm_errstring(errno));
540                         (void) closesocket(sock);
541                         return INVALID_SOCKET;
542                 }
543         }
544 #endif /* NETUNIX */
545         L_family = addr.sa.sa_family;
546         return sock;
547 }
548 /*
549 **  MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
550 **
551 **      Parameters:
552 **              arg -- argument to pass to mi_handle_session()
553 **
554 **      Returns:
555 **              results from mi_handle_session()
556 */
557
558 static void *
559 mi_thread_handle_wrapper(arg)
560         void *arg;
561 {
562         return (void *) mi_handle_session(arg);
563 }
564
565 /*
566 **  MI_CLOSENER -- close listen socket
567 **
568 **      NOTE: It is assumed that this function is called from a
569 **            function that has a mutex lock (currently mi_stop_milters()).
570 **
571 **      Parameters:
572 **              none.
573 **
574 **      Returns:
575 **              none.
576 */
577
578 void
579 mi_closener()
580 {
581         (void) smutex_lock(&L_Mutex);
582         if (ValidSocket(listenfd))
583         {
584 #if NETUNIX
585                 bool removable;
586                 struct stat sockinfo;
587                 struct stat fileinfo;
588
589                 removable = sockpath != NULL &&
590                             geteuid() != 0 &&
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 **              smfi -- filter structure to use
639 **              timeout -- timeout for reads/writes
640 **              backlog -- listen queue backlog size
641 **
642 **      Returns:
643 **              MI_SUCCESS -- Exited normally
644 **                         (session finished or we were told to exit)
645 **              MI_FAILURE -- Network initialization failed.
646 */
647
648 #if BROKEN_PTHREAD_SLEEP
649
650 /*
651 **  Solaris 2.6, perhaps others, gets an internal threads library panic
652 **  when sleep() is used:
653 **
654 **  thread_create() failed, returned 11 (EINVAL)
655 **  co_enable, thr_create() returned error = 24
656 **  libthread panic: co_enable failed (PID: 17793 LWP 1)
657 **  stacktrace:
658 **      ef526b10
659 **      ef52646c
660 **      ef534cbc
661 **      156a4
662 **      14644
663 **      1413c
664 **      135e0
665 **      0
666 */
667
668 # define MI_SLEEP(s)                                                    \
669 {                                                                       \
670         int rs = 0;                                                     \
671         struct timeval st;                                              \
672                                                                         \
673         st.tv_sec = (s);                                                \
674         st.tv_usec = 0;                                                 \
675         if (st.tv_sec > 0)                                              \
676         {                                                               \
677                 for (;;)                                                \
678                 {                                                       \
679                         rs = select(0, NULL, NULL, NULL, &st);          \
680                         if (rs < 0 && errno == EINTR)                   \
681                                 continue;                               \
682                         if (rs != 0)                                    \
683                         {                                               \
684                                 smi_log(SMI_LOG_ERR,                    \
685                                         "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
686                                         rs, errno);                     \
687                         }                                               \
688                         break;                                          \
689                 }                                                       \
690         }                                                               \
691 }
692 #else /* BROKEN_PTHREAD_SLEEP */
693 # define MI_SLEEP(s)    sleep((s))
694 #endif /* BROKEN_PTHREAD_SLEEP */
695
696 int
697 mi_listener(conn, dbg, smfi, timeout, backlog)
698         char *conn;
699         int dbg;
700         smfiDesc_ptr smfi;
701         time_t timeout;
702         int backlog;
703 {
704         socket_t connfd = INVALID_SOCKET;
705 #if _FFR_DUP_FD
706         socket_t dupfd = INVALID_SOCKET;
707 #endif /* _FFR_DUP_FD */
708         int sockopt = 1;
709         int r, mistop;
710         int ret = MI_SUCCESS;
711         int mcnt = 0;   /* error count for malloc() failures */
712         int tcnt = 0;   /* error count for thread_create() failures */
713         int acnt = 0;   /* error count for accept() failures */
714         int scnt = 0;   /* error count for select() failures */
715         int save_errno = 0;
716         sthread_t thread_id;
717         _SOCK_ADDR cliaddr;
718         SOCKADDR_LEN_T clilen;
719         SMFICTX_PTR ctx;
720         FD_RD_VAR(rds, excs);
721         struct timeval chktime;
722
723         if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
724                 return MI_FAILURE;
725
726         clilen = L_socksize;
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 !SM_CONF_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 /* !SM_CONF_POLL */
814
815                 if (!ValidSocket(connfd))
816                 {
817                         if (save_errno == EINTR
818 #ifdef EAGAIN
819                             || save_errno == EAGAIN
820 #endif /* EAGAIN */
821 #ifdef ECONNABORTED
822                             || save_errno == ECONNABORTED
823 #endif /* ECONNABORTED */
824 #ifdef EMFILE
825                             || save_errno == EMFILE
826 #endif /* EMFILE */
827 #ifdef ENFILE
828                             || save_errno == ENFILE
829 #endif /* ENFILE */
830 #ifdef ENOBUFS
831                             || save_errno == ENOBUFS
832 #endif /* ENOBUFS */
833 #ifdef ENOMEM
834                             || save_errno == ENOMEM
835 #endif /* ENOMEM */
836 #ifdef ENOSR
837                             || save_errno == ENOSR
838 #endif /* ENOSR */
839 #ifdef EWOULDBLOCK
840                             || save_errno == EWOULDBLOCK
841 #endif /* EWOULDBLOCK */
842                            )
843                                 continue;
844                         acnt++;
845                         smi_log(SMI_LOG_ERR,
846                                 "%s: accept() returned invalid socket (%s), %s",
847                                 smfi->xxfi_name, sm_errstring(save_errno),
848                                 acnt >= MAX_FAILS_A ? "abort" : "try again");
849                         MI_SLEEP(acnt);
850                         if (acnt >= MAX_FAILS_A)
851                         {
852                                 ret = MI_FAILURE;
853                                 break;
854                         }
855                         continue;
856                 }
857                 acnt = 0;       /* reset error counter for accept() */
858 #if _FFR_DUP_FD
859                 dupfd = fcntl(connfd, F_DUPFD, 256);
860                 if (ValidSocket(dupfd)
861 # if !SM_CONF_POLL
862                     && SM_FD_OK_SELECT(dupfd)
863 # endif /* !SM_CONF_POLL */
864                    )
865                 {
866                         close(connfd);
867                         connfd = dupfd;
868                         dupfd = INVALID_SOCKET;
869                 }
870 #endif /* _FFR_DUP_FD */
871
872                 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
873                                 (void *) &sockopt, sizeof sockopt) < 0)
874                 {
875                         smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)",
876                                 smfi->xxfi_name, sm_errstring(errno));
877                         /* XXX: continue? */
878                 }
879                 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
880                 {
881                         (void) closesocket(connfd);
882                         mcnt++;
883                         smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
884                                 smfi->xxfi_name, sm_errstring(save_errno),
885                                 mcnt >= MAX_FAILS_M ? "abort" : "try again");
886                         MI_SLEEP(mcnt);
887                         if (mcnt >= MAX_FAILS_M)
888                         {
889                                 ret = MI_FAILURE;
890                                 break;
891                         }
892                         continue;
893                 }
894                 mcnt = 0;       /* reset error counter for malloc() */
895                 (void) memset(ctx, '\0', sizeof *ctx);
896                 ctx->ctx_sd = connfd;
897                 ctx->ctx_dbg = dbg;
898                 ctx->ctx_timeout = timeout;
899                 ctx->ctx_smfi = smfi;
900 #if 0
901                 if (smfi->xxfi_eoh == NULL)
902                 if (smfi->xxfi_eom == NULL)
903                 if (smfi->xxfi_abort == NULL)
904                 if (smfi->xxfi_close == NULL)
905 #endif /* 0 */
906                 if (smfi->xxfi_connect == NULL)
907                         ctx->ctx_pflags |= SMFIP_NOCONNECT;
908                 if (smfi->xxfi_helo == NULL)
909                         ctx->ctx_pflags |= SMFIP_NOHELO;
910                 if (smfi->xxfi_envfrom == NULL)
911                         ctx->ctx_pflags |= SMFIP_NOMAIL;
912                 if (smfi->xxfi_envrcpt == NULL)
913                         ctx->ctx_pflags |= SMFIP_NORCPT;
914                 if (smfi->xxfi_header == NULL)
915                         ctx->ctx_pflags |= SMFIP_NOHDRS;
916                 if (smfi->xxfi_eoh == NULL)
917                         ctx->ctx_pflags |= SMFIP_NOEOH;
918                 if (smfi->xxfi_body == NULL)
919                         ctx->ctx_pflags |= SMFIP_NOBODY;
920
921                 if ((r = thread_create(&thread_id,
922                                         mi_thread_handle_wrapper,
923                                         (void *) ctx)) != 0)
924                 {
925                         tcnt++;
926                         smi_log(SMI_LOG_ERR,
927                                 "%s: thread_create() failed: %d, %s",
928                                 smfi->xxfi_name,  r,
929                                 tcnt >= MAX_FAILS_T ? "abort" : "try again");
930                         MI_SLEEP(tcnt);
931                         (void) closesocket(connfd);
932                         free(ctx);
933                         if (tcnt >= MAX_FAILS_T)
934                         {
935                                 ret = MI_FAILURE;
936                                 break;
937                         }
938                         continue;
939                 }
940                 tcnt = 0;
941         }
942         if (ret != MI_SUCCESS)
943                 mi_stop_milters(MILTER_ABRT);
944         else
945         {
946                 if (mistop != MILTER_CONT)
947                         smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
948                                 smfi->xxfi_name, mistop);
949                 mi_closener();
950         }
951         (void) smutex_destroy(&L_Mutex);
952         return ret;
953 }