1 /* 2 * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11 #pragma ident "%Z%%M% %I% %E% SMI" 12 13 #include <sm/gen.h> 14 SM_RCSID("@(#)$Id: listener.c,v 8.111 2004/09/20 21:11:15 msk 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 (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 464 sizeof(sockopt)) == -1) 465 { 466 smi_log(SMI_LOG_ERR, 467 "%s: Unable to setsockopt: %s", name, 468 sm_errstring(errno)); 469 (void) closesocket(sock); 470 return INVALID_SOCKET; 471 } 472 473 #if NETUNIX 474 if (addr.sa.sa_family == AF_UNIX && rmsocket) 475 { 476 struct stat s; 477 478 if (stat(colon, &s) != 0) 479 { 480 if (errno != ENOENT) 481 { 482 smi_log(SMI_LOG_ERR, 483 "%s: Unable to stat() %s: %s", 484 name, colon, sm_errstring(errno)); 485 (void) closesocket(sock); 486 return INVALID_SOCKET; 487 } 488 } 489 else if (!S_ISSOCK(s.st_mode)) 490 { 491 smi_log(SMI_LOG_ERR, 492 "%s: %s is not a UNIX domain socket", 493 name, colon); 494 (void) closesocket(sock); 495 return INVALID_SOCKET; 496 } 497 else if (unlink(colon) != 0) 498 { 499 smi_log(SMI_LOG_ERR, 500 "%s: Unable to remove %s: %s", 501 name, colon, sm_errstring(errno)); 502 (void) closesocket(sock); 503 return INVALID_SOCKET; 504 } 505 } 506 #endif /* NETUNIX */ 507 508 if (bind(sock, &addr.sa, L_socksize) < 0) 509 { 510 smi_log(SMI_LOG_ERR, 511 "%s: Unable to bind to port %s: %s", 512 name, conn, sm_errstring(errno)); 513 (void) closesocket(sock); 514 return INVALID_SOCKET; 515 } 516 517 if (listen(sock, backlog) < 0) 518 { 519 smi_log(SMI_LOG_ERR, 520 "%s: listen call failed: %s", name, 521 sm_errstring(errno)); 522 (void) closesocket(sock); 523 return INVALID_SOCKET; 524 } 525 526 #if NETUNIX 527 if (addr.sa.sa_family == AF_UNIX && len > 0) 528 { 529 /* 530 ** Set global variable sockpath so the UNIX socket can be 531 ** unlink()ed at exit. 532 */ 533 534 sockpath = (char *) malloc(len); 535 if (sockpath != NULL) 536 (void) sm_strlcpy(sockpath, colon, len); 537 else 538 { 539 smi_log(SMI_LOG_ERR, 540 "%s: can't malloc(%d) for sockpath: %s", 541 name, (int) len, sm_errstring(errno)); 542 (void) closesocket(sock); 543 return INVALID_SOCKET; 544 } 545 } 546 #endif /* NETUNIX */ 547 L_family = addr.sa.sa_family; 548 return sock; 549 } 550 /* 551 ** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 552 ** 553 ** Parameters: 554 ** arg -- argument to pass to mi_handle_session() 555 ** 556 ** Returns: 557 ** results from mi_handle_session() 558 */ 559 560 static void * 561 mi_thread_handle_wrapper(arg) 562 void *arg; 563 { 564 return (void *) mi_handle_session(arg); 565 } 566 567 /* 568 ** MI_CLOSENER -- close listen socket 569 ** 570 ** NOTE: It is assumed that this function is called from a 571 ** function that has a mutex lock (currently mi_stop_milters()). 572 ** 573 ** Parameters: 574 ** none. 575 ** 576 ** Returns: 577 ** none. 578 */ 579 580 void 581 mi_closener() 582 { 583 (void) smutex_lock(&L_Mutex); 584 if (ValidSocket(listenfd)) 585 { 586 #if NETUNIX 587 bool removable; 588 struct stat sockinfo; 589 struct stat fileinfo; 590 591 removable = sockpath != NULL && 592 geteuid() != 0 && 593 fstat(listenfd, &sockinfo) == 0 && 594 (S_ISFIFO(sockinfo.st_mode) 595 # ifdef S_ISSOCK 596 || S_ISSOCK(sockinfo.st_mode) 597 # endif /* S_ISSOCK */ 598 ); 599 #endif /* NETUNIX */ 600 601 (void) closesocket(listenfd); 602 listenfd = INVALID_SOCKET; 603 604 #if NETUNIX 605 /* XXX sleep() some time before doing this? */ 606 if (sockpath != NULL) 607 { 608 if (removable && 609 stat(sockpath, &fileinfo) == 0 && 610 ((fileinfo.st_dev == sockinfo.st_dev && 611 fileinfo.st_ino == sockinfo.st_ino) 612 # ifdef S_ISSOCK 613 || S_ISSOCK(fileinfo.st_mode) 614 # endif /* S_ISSOCK */ 615 ) 616 && 617 (S_ISFIFO(fileinfo.st_mode) 618 # ifdef S_ISSOCK 619 || S_ISSOCK(fileinfo.st_mode) 620 # endif /* S_ISSOCK */ 621 )) 622 (void) unlink(sockpath); 623 free(sockpath); 624 sockpath = NULL; 625 } 626 #endif /* NETUNIX */ 627 } 628 (void) smutex_unlock(&L_Mutex); 629 } 630 631 /* 632 ** MI_LISTENER -- Generic listener harness 633 ** 634 ** Open up listen port 635 ** Wait for connections 636 ** 637 ** Parameters: 638 ** conn -- connection description 639 ** dbg -- debug level 640 ** smfi -- filter structure to use 641 ** timeout -- timeout for reads/writes 642 ** backlog -- listen queue backlog size 643 ** 644 ** Returns: 645 ** MI_SUCCESS -- Exited normally 646 ** (session finished or we were told to exit) 647 ** MI_FAILURE -- Network initialization failed. 648 */ 649 650 #if BROKEN_PTHREAD_SLEEP 651 652 /* 653 ** Solaris 2.6, perhaps others, gets an internal threads library panic 654 ** when sleep() is used: 655 ** 656 ** thread_create() failed, returned 11 (EINVAL) 657 ** co_enable, thr_create() returned error = 24 658 ** libthread panic: co_enable failed (PID: 17793 LWP 1) 659 ** stacktrace: 660 ** ef526b10 661 ** ef52646c 662 ** ef534cbc 663 ** 156a4 664 ** 14644 665 ** 1413c 666 ** 135e0 667 ** 0 668 */ 669 670 # define MI_SLEEP(s) \ 671 { \ 672 int rs = 0; \ 673 struct timeval st; \ 674 \ 675 st.tv_sec = (s); \ 676 st.tv_usec = 0; \ 677 if (st.tv_sec > 0) \ 678 { \ 679 for (;;) \ 680 { \ 681 rs = select(0, NULL, NULL, NULL, &st); \ 682 if (rs < 0 && errno == EINTR) \ 683 continue; \ 684 if (rs != 0) \ 685 { \ 686 smi_log(SMI_LOG_ERR, \ 687 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ 688 rs, errno); \ 689 } \ 690 break; \ 691 } \ 692 } \ 693 } 694 #else /* BROKEN_PTHREAD_SLEEP */ 695 # define MI_SLEEP(s) sleep((s)) 696 #endif /* BROKEN_PTHREAD_SLEEP */ 697 698 int 699 mi_listener(conn, dbg, smfi, timeout, backlog) 700 char *conn; 701 int dbg; 702 smfiDesc_ptr smfi; 703 time_t timeout; 704 int backlog; 705 { 706 socket_t connfd = INVALID_SOCKET; 707 #if _FFR_DUP_FD 708 socket_t dupfd = INVALID_SOCKET; 709 #endif /* _FFR_DUP_FD */ 710 int sockopt = 1; 711 int r, mistop; 712 int ret = MI_SUCCESS; 713 int mcnt = 0; /* error count for malloc() failures */ 714 int tcnt = 0; /* error count for thread_create() failures */ 715 int acnt = 0; /* error count for accept() failures */ 716 int scnt = 0; /* error count for select() failures */ 717 int save_errno = 0; 718 sthread_t thread_id; 719 _SOCK_ADDR cliaddr; 720 SOCKADDR_LEN_T clilen; 721 SMFICTX_PTR ctx; 722 FD_RD_VAR(rds, excs); 723 struct timeval chktime; 724 725 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE) 726 return MI_FAILURE; 727 728 clilen = L_socksize; 729 while ((mistop = mi_stop()) == MILTER_CONT) 730 { 731 (void) smutex_lock(&L_Mutex); 732 if (!ValidSocket(listenfd)) 733 { 734 ret = MI_FAILURE; 735 smi_log(SMI_LOG_ERR, 736 "%s: listenfd=%d corrupted, terminating, errno=%d", 737 smfi->xxfi_name, listenfd, errno); 738 (void) smutex_unlock(&L_Mutex); 739 break; 740 } 741 742 /* select on interface ports */ 743 FD_RD_INIT(listenfd, rds, excs); 744 chktime.tv_sec = MI_CHK_TIME; 745 chktime.tv_usec = 0; 746 r = FD_RD_READY(listenfd, rds, excs, &chktime); 747 if (r == 0) /* timeout */ 748 { 749 (void) smutex_unlock(&L_Mutex); 750 continue; /* just check mi_stop() */ 751 } 752 if (r < 0) 753 { 754 save_errno = errno; 755 (void) smutex_unlock(&L_Mutex); 756 if (save_errno == EINTR) 757 continue; 758 scnt++; 759 smi_log(SMI_LOG_ERR, 760 "%s: select() failed (%s), %s", 761 smfi->xxfi_name, sm_errstring(save_errno), 762 scnt >= MAX_FAILS_S ? "abort" : "try again"); 763 MI_SLEEP(scnt); 764 if (scnt >= MAX_FAILS_S) 765 { 766 ret = MI_FAILURE; 767 break; 768 } 769 continue; 770 } 771 if (!FD_IS_RD_RDY(listenfd, rds, excs)) 772 { 773 /* some error: just stop for now... */ 774 ret = MI_FAILURE; 775 (void) smutex_unlock(&L_Mutex); 776 smi_log(SMI_LOG_ERR, 777 "%s: %s() returned exception for socket, abort", 778 smfi->xxfi_name, MI_POLLSELECT); 779 break; 780 } 781 scnt = 0; /* reset error counter for select() */ 782 783 (void) memset(&cliaddr, '\0', sizeof cliaddr); 784 connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 785 &clilen); 786 save_errno = errno; 787 (void) smutex_unlock(&L_Mutex); 788 789 /* 790 ** If remote side closes before 791 ** accept() finishes, sockaddr 792 ** might not be fully filled in. 793 */ 794 795 if (ValidSocket(connfd) && 796 (clilen == 0 || 797 # ifdef BSD4_4_SOCKADDR 798 cliaddr.sa.sa_len == 0 || 799 # endif /* BSD4_4_SOCKADDR */ 800 cliaddr.sa.sa_family != L_family)) 801 { 802 (void) closesocket(connfd); 803 connfd = INVALID_SOCKET; 804 save_errno = EINVAL; 805 } 806 807 #if !SM_CONF_POLL 808 /* check if acceptable for select() */ 809 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd)) 810 { 811 (void) closesocket(connfd); 812 connfd = INVALID_SOCKET; 813 save_errno = ERANGE; 814 } 815 #endif /* !SM_CONF_POLL */ 816 817 if (!ValidSocket(connfd)) 818 { 819 if (save_errno == EINTR 820 #ifdef EAGAIN 821 || save_errno == EAGAIN 822 #endif /* EAGAIN */ 823 #ifdef ECONNABORTED 824 || save_errno == ECONNABORTED 825 #endif /* ECONNABORTED */ 826 #ifdef EMFILE 827 || save_errno == EMFILE 828 #endif /* EMFILE */ 829 #ifdef ENFILE 830 || save_errno == ENFILE 831 #endif /* ENFILE */ 832 #ifdef ENOBUFS 833 || save_errno == ENOBUFS 834 #endif /* ENOBUFS */ 835 #ifdef ENOMEM 836 || save_errno == ENOMEM 837 #endif /* ENOMEM */ 838 #ifdef ENOSR 839 || save_errno == ENOSR 840 #endif /* ENOSR */ 841 #ifdef EWOULDBLOCK 842 || save_errno == EWOULDBLOCK 843 #endif /* EWOULDBLOCK */ 844 ) 845 continue; 846 acnt++; 847 smi_log(SMI_LOG_ERR, 848 "%s: accept() returned invalid socket (%s), %s", 849 smfi->xxfi_name, sm_errstring(save_errno), 850 acnt >= MAX_FAILS_A ? "abort" : "try again"); 851 MI_SLEEP(acnt); 852 if (acnt >= MAX_FAILS_A) 853 { 854 ret = MI_FAILURE; 855 break; 856 } 857 continue; 858 } 859 acnt = 0; /* reset error counter for accept() */ 860 #if _FFR_DUP_FD 861 dupfd = fcntl(connfd, F_DUPFD, 256); 862 if (ValidSocket(dupfd) 863 # if !SM_CONF_POLL 864 && SM_FD_OK_SELECT(dupfd) 865 # endif /* !SM_CONF_POLL */ 866 ) 867 { 868 close(connfd); 869 connfd = dupfd; 870 dupfd = INVALID_SOCKET; 871 } 872 #endif /* _FFR_DUP_FD */ 873 874 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 875 (void *) &sockopt, sizeof sockopt) < 0) 876 { 877 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)", 878 smfi->xxfi_name, sm_errstring(errno)); 879 /* XXX: continue? */ 880 } 881 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 882 { 883 (void) closesocket(connfd); 884 mcnt++; 885 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s", 886 smfi->xxfi_name, sm_errstring(save_errno), 887 mcnt >= MAX_FAILS_M ? "abort" : "try again"); 888 MI_SLEEP(mcnt); 889 if (mcnt >= MAX_FAILS_M) 890 { 891 ret = MI_FAILURE; 892 break; 893 } 894 continue; 895 } 896 mcnt = 0; /* reset error counter for malloc() */ 897 (void) memset(ctx, '\0', sizeof *ctx); 898 ctx->ctx_sd = connfd; 899 ctx->ctx_dbg = dbg; 900 ctx->ctx_timeout = timeout; 901 ctx->ctx_smfi = smfi; 902 #if 0 903 if (smfi->xxfi_eoh == NULL) 904 if (smfi->xxfi_eom == NULL) 905 if (smfi->xxfi_abort == NULL) 906 if (smfi->xxfi_close == NULL) 907 #endif /* 0 */ 908 if (smfi->xxfi_connect == NULL) 909 ctx->ctx_pflags |= SMFIP_NOCONNECT; 910 if (smfi->xxfi_helo == NULL) 911 ctx->ctx_pflags |= SMFIP_NOHELO; 912 if (smfi->xxfi_envfrom == NULL) 913 ctx->ctx_pflags |= SMFIP_NOMAIL; 914 if (smfi->xxfi_envrcpt == NULL) 915 ctx->ctx_pflags |= SMFIP_NORCPT; 916 if (smfi->xxfi_header == NULL) 917 ctx->ctx_pflags |= SMFIP_NOHDRS; 918 if (smfi->xxfi_eoh == NULL) 919 ctx->ctx_pflags |= SMFIP_NOEOH; 920 if (smfi->xxfi_body == NULL) 921 ctx->ctx_pflags |= SMFIP_NOBODY; 922 923 if ((r = thread_create(&thread_id, 924 mi_thread_handle_wrapper, 925 (void *) ctx)) != 0) 926 { 927 tcnt++; 928 smi_log(SMI_LOG_ERR, 929 "%s: thread_create() failed: %d, %s", 930 smfi->xxfi_name, r, 931 tcnt >= MAX_FAILS_T ? "abort" : "try again"); 932 MI_SLEEP(tcnt); 933 (void) closesocket(connfd); 934 free(ctx); 935 if (tcnt >= MAX_FAILS_T) 936 { 937 ret = MI_FAILURE; 938 break; 939 } 940 continue; 941 } 942 tcnt = 0; 943 } 944 if (ret != MI_SUCCESS) 945 mi_stop_milters(MILTER_ABRT); 946 else 947 { 948 if (mistop != MILTER_CONT) 949 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d", 950 smfi->xxfi_name, mistop); 951 mi_closener(); 952 } 953 (void) smutex_destroy(&L_Mutex); 954 return ret; 955 } 956