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