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