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