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