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