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