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