listener.c revision 261363
1230557Sjimharris/* 2230557Sjimharris * Copyright (c) 1999-2007 Proofpoint, Inc. and its suppliers. 3230557Sjimharris * All rights reserved. 4230557Sjimharris * 5230557Sjimharris * By using this file, you agree to the terms and conditions set 6230557Sjimharris * forth in the LICENSE file which can be found at the top level of 7230557Sjimharris * the sendmail distribution. 8230557Sjimharris * 9230557Sjimharris */ 10230557Sjimharris 11230557Sjimharris#include <sm/gen.h> 12230557SjimharrisSM_RCSID("@(#)$Id: listener.c,v 8.127 2013/11/22 20:51:36 ca Exp $") 13230557Sjimharris 14230557Sjimharris/* 15230557Sjimharris** listener.c -- threaded network listener 16230557Sjimharris*/ 17230557Sjimharris 18230557Sjimharris#include "libmilter.h" 19230557Sjimharris#include <sm/errstring.h> 20230557Sjimharris 21230557Sjimharris#include <sys/types.h> 22230557Sjimharris#include <sys/stat.h> 23230557Sjimharris 24230557Sjimharris 25230557Sjimharris# if NETINET || NETINET6 26230557Sjimharris# include <arpa/inet.h> 27230557Sjimharris# endif /* NETINET || NETINET6 */ 28230557Sjimharris# if SM_CONF_POLL 29230557Sjimharris# undef SM_FD_OK_SELECT 30230557Sjimharris# define SM_FD_OK_SELECT(fd) true 31230557Sjimharris# endif /* SM_CONF_POLL */ 32230557Sjimharris 33230557Sjimharrisstatic smutex_t L_Mutex; 34230557Sjimharrisstatic int L_family; 35230557Sjimharrisstatic SOCKADDR_LEN_T L_socksize; 36230557Sjimharrisstatic socket_t listenfd = INVALID_SOCKET; 37230557Sjimharris 38230557Sjimharrisstatic socket_t mi_milteropen __P((char *, int, bool, char *)); 39230557Sjimharris#if !_FFR_WORKERS_POOL 40230557Sjimharrisstatic void *mi_thread_handle_wrapper __P((void *)); 41230557Sjimharris#endif /* !_FFR_WORKERS_POOL */ 42230557Sjimharris 43230557Sjimharris/* 44230557Sjimharris** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet 45230557Sjimharris** 46230557Sjimharris** Parameters: 47230557Sjimharris** conn -- connection description 48230557Sjimharris** backlog -- listen backlog 49230557Sjimharris** dbg -- debug level 50230557Sjimharris** rmsocket -- if true, try to unlink() the socket first 51230557Sjimharris** (UNIX domain sockets only) 52230557Sjimharris** smfi -- filter structure to use 53230557Sjimharris** 54230557Sjimharris** Return value: 55230557Sjimharris** MI_SUCCESS/MI_FAILURE 56230557Sjimharris*/ 57230557Sjimharris 58230557Sjimharrisint 59230557Sjimharrismi_opensocket(conn, backlog, dbg, rmsocket, smfi) 60230557Sjimharris char *conn; 61230557Sjimharris int backlog; 62230557Sjimharris int dbg; 63230557Sjimharris bool rmsocket; 64230557Sjimharris smfiDesc_ptr smfi; 65230557Sjimharris{ 66230557Sjimharris if (smfi == NULL || conn == NULL) 67230557Sjimharris return MI_FAILURE; 68230557Sjimharris 69230557Sjimharris if (ValidSocket(listenfd)) 70230557Sjimharris return MI_SUCCESS; 71230557Sjimharris 72230557Sjimharris if (dbg > 0) 73230557Sjimharris { 74230557Sjimharris smi_log(SMI_LOG_DEBUG, 75230557Sjimharris "%s: Opening listen socket on conn %s", 76230557Sjimharris smfi->xxfi_name, conn); 77230557Sjimharris } 78230557Sjimharris (void) smutex_init(&L_Mutex); 79230557Sjimharris (void) smutex_lock(&L_Mutex); 80230557Sjimharris listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name); 81230557Sjimharris if (!ValidSocket(listenfd)) 82230557Sjimharris { 83230557Sjimharris smi_log(SMI_LOG_FATAL, 84230557Sjimharris "%s: Unable to create listening socket on conn %s", 85230557Sjimharris smfi->xxfi_name, conn); 86230557Sjimharris (void) smutex_unlock(&L_Mutex); 87230557Sjimharris return MI_FAILURE; 88230557Sjimharris } 89230557Sjimharris if (!SM_FD_OK_SELECT(listenfd)) 90230557Sjimharris { 91230557Sjimharris smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 92230557Sjimharris smfi->xxfi_name, listenfd, FD_SETSIZE); 93230557Sjimharris (void) smutex_unlock(&L_Mutex); 94230557Sjimharris return MI_FAILURE; 95230557Sjimharris } 96230557Sjimharris (void) smutex_unlock(&L_Mutex); 97230557Sjimharris return MI_SUCCESS; 98230557Sjimharris} 99230557Sjimharris 100230557Sjimharris/* 101230557Sjimharris** MI_MILTEROPEN -- setup socket to listen on 102230557Sjimharris** 103230557Sjimharris** Parameters: 104230557Sjimharris** conn -- connection description 105230557Sjimharris** backlog -- listen backlog 106230557Sjimharris** rmsocket -- if true, try to unlink() the socket first 107230557Sjimharris** (UNIX domain sockets only) 108230557Sjimharris** name -- name for logging 109230557Sjimharris** 110230557Sjimharris** Returns: 111230557Sjimharris** socket upon success, error code otherwise. 112230557Sjimharris** 113230557Sjimharris** Side effect: 114230557Sjimharris** sets sockpath if UNIX socket. 115230557Sjimharris*/ 116230557Sjimharris 117230557Sjimharris#if NETUNIX 118230557Sjimharrisstatic char *sockpath = NULL; 119230557Sjimharris#endif /* NETUNIX */ 120230557Sjimharris 121230557Sjimharrisstatic socket_t 122230557Sjimharrismi_milteropen(conn, backlog, rmsocket, name) 123230557Sjimharris char *conn; 124230557Sjimharris int backlog; 125230557Sjimharris bool rmsocket; 126230557Sjimharris char *name; 127230557Sjimharris{ 128230557Sjimharris socket_t sock; 129230557Sjimharris int sockopt = 1; 130230557Sjimharris int fdflags; 131230557Sjimharris size_t len = 0; 132230557Sjimharris char *p; 133230557Sjimharris char *colon; 134230557Sjimharris char *at; 135230557Sjimharris SOCKADDR addr; 136230557Sjimharris 137230557Sjimharris if (conn == NULL || conn[0] == '\0') 138230557Sjimharris { 139230557Sjimharris smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", 140230557Sjimharris name); 141230557Sjimharris return INVALID_SOCKET; 142230557Sjimharris } 143230557Sjimharris (void) memset(&addr, '\0', sizeof addr); 144230557Sjimharris 145230557Sjimharris /* protocol:filename or protocol:port@host */ 146230557Sjimharris p = conn; 147230557Sjimharris colon = strchr(p, ':'); 148230557Sjimharris if (colon != NULL) 149230557Sjimharris { 150230557Sjimharris *colon = '\0'; 151230557Sjimharris 152230557Sjimharris if (*p == '\0') 153230557Sjimharris { 154230557Sjimharris#if NETUNIX 155230557Sjimharris /* default to AF_UNIX */ 156230557Sjimharris addr.sa.sa_family = AF_UNIX; 157230557Sjimharris L_socksize = sizeof (struct sockaddr_un); 158230557Sjimharris#else /* NETUNIX */ 159230557Sjimharris# if NETINET 160230557Sjimharris /* default to AF_INET */ 161230557Sjimharris addr.sa.sa_family = AF_INET; 162230557Sjimharris L_socksize = sizeof addr.sin; 163230557Sjimharris# else /* NETINET */ 164230557Sjimharris# if NETINET6 165230557Sjimharris /* default to AF_INET6 */ 166230557Sjimharris addr.sa.sa_family = AF_INET6; 167230557Sjimharris L_socksize = sizeof addr.sin6; 168230557Sjimharris# else /* NETINET6 */ 169230557Sjimharris /* no protocols available */ 170230557Sjimharris smi_log(SMI_LOG_ERR, 171230557Sjimharris "%s: no valid socket protocols available", 172230557Sjimharris name); 173230557Sjimharris return INVALID_SOCKET; 174230557Sjimharris# endif /* NETINET6 */ 175230557Sjimharris# endif /* NETINET */ 176230557Sjimharris#endif /* NETUNIX */ 177230557Sjimharris } 178230557Sjimharris#if NETUNIX 179230557Sjimharris else if (strcasecmp(p, "unix") == 0 || 180230557Sjimharris strcasecmp(p, "local") == 0) 181230557Sjimharris { 182230557Sjimharris addr.sa.sa_family = AF_UNIX; 183230557Sjimharris L_socksize = sizeof (struct sockaddr_un); 184230557Sjimharris } 185230557Sjimharris#endif /* NETUNIX */ 186230557Sjimharris#if NETINET 187230557Sjimharris else if (strcasecmp(p, "inet") == 0) 188230557Sjimharris { 189230557Sjimharris addr.sa.sa_family = AF_INET; 190230557Sjimharris L_socksize = sizeof addr.sin; 191230557Sjimharris } 192230557Sjimharris#endif /* NETINET */ 193230557Sjimharris#if NETINET6 194230557Sjimharris else if (strcasecmp(p, "inet6") == 0) 195230557Sjimharris { 196230557Sjimharris addr.sa.sa_family = AF_INET6; 197230557Sjimharris L_socksize = sizeof addr.sin6; 198230557Sjimharris } 199230557Sjimharris#endif /* NETINET6 */ 200230557Sjimharris else 201230557Sjimharris { 202230557Sjimharris smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 203230557Sjimharris name, p); 204230557Sjimharris return INVALID_SOCKET; 205230557Sjimharris } 206230557Sjimharris *colon++ = ':'; 207230557Sjimharris } 208230557Sjimharris else 209230557Sjimharris { 210230557Sjimharris colon = p; 211230557Sjimharris#if NETUNIX 212230557Sjimharris /* default to AF_UNIX */ 213230557Sjimharris addr.sa.sa_family = AF_UNIX; 214230557Sjimharris L_socksize = sizeof (struct sockaddr_un); 215230557Sjimharris#else /* NETUNIX */ 216230557Sjimharris# if NETINET 217230557Sjimharris /* default to AF_INET */ 218230557Sjimharris addr.sa.sa_family = AF_INET; 219230557Sjimharris L_socksize = sizeof addr.sin; 220230557Sjimharris# else /* NETINET */ 221230557Sjimharris# if NETINET6 222230557Sjimharris /* default to AF_INET6 */ 223230557Sjimharris addr.sa.sa_family = AF_INET6; 224230557Sjimharris L_socksize = sizeof addr.sin6; 225230557Sjimharris# else /* NETINET6 */ 226230557Sjimharris smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 227230557Sjimharris name, p); 228230557Sjimharris return INVALID_SOCKET; 229230557Sjimharris# endif /* NETINET6 */ 230230557Sjimharris# endif /* NETINET */ 231230557Sjimharris#endif /* NETUNIX */ 232230557Sjimharris } 233230557Sjimharris 234230557Sjimharris#if NETUNIX 235230557Sjimharris if (addr.sa.sa_family == AF_UNIX) 236230557Sjimharris { 237230557Sjimharris# if 0 238230557Sjimharris long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 239230557Sjimharris# endif /* 0 */ 240230557Sjimharris 241230557Sjimharris at = colon; 242230557Sjimharris len = strlen(colon) + 1; 243230557Sjimharris if (len >= sizeof addr.sunix.sun_path) 244230557Sjimharris { 245230557Sjimharris errno = EINVAL; 246230557Sjimharris smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", 247230557Sjimharris name, colon); 248230557Sjimharris return INVALID_SOCKET; 249230557Sjimharris } 250230557Sjimharris (void) sm_strlcpy(addr.sunix.sun_path, colon, 251230557Sjimharris sizeof addr.sunix.sun_path); 252230557Sjimharris# if 0 253230557Sjimharris errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 254230557Sjimharris S_IRUSR|S_IWUSR, NULL); 255230557Sjimharris 256230557Sjimharris /* if not safe, don't create */ 257230557Sjimharris if (errno != 0) 258230557Sjimharris { 259230557Sjimharris smi_log(SMI_LOG_ERR, 260230557Sjimharris "%s: UNIX socket name %s unsafe", 261230557Sjimharris name, colon); 262230557Sjimharris return INVALID_SOCKET; 263230557Sjimharris } 264230557Sjimharris# endif /* 0 */ 265230557Sjimharris } 266230557Sjimharris#endif /* NETUNIX */ 267230557Sjimharris 268230557Sjimharris#if NETINET || NETINET6 269230557Sjimharris if ( 270230557Sjimharris# if NETINET 271230557Sjimharris addr.sa.sa_family == AF_INET 272230557Sjimharris# endif /* NETINET */ 273230557Sjimharris# if NETINET && NETINET6 274230557Sjimharris || 275230557Sjimharris# endif /* NETINET && NETINET6 */ 276230557Sjimharris# if NETINET6 277230557Sjimharris addr.sa.sa_family == AF_INET6 278230557Sjimharris# endif /* NETINET6 */ 279230557Sjimharris ) 280230557Sjimharris { 281230557Sjimharris unsigned short port; 282230557Sjimharris 283230557Sjimharris /* Parse port@host */ 284230557Sjimharris at = strchr(colon, '@'); 285230557Sjimharris if (at == NULL) 286230557Sjimharris { 287230557Sjimharris switch (addr.sa.sa_family) 288230557Sjimharris { 289230557Sjimharris# if NETINET 290230557Sjimharris case AF_INET: 291230557Sjimharris addr.sin.sin_addr.s_addr = INADDR_ANY; 292230557Sjimharris break; 293230557Sjimharris# endif /* NETINET */ 294230557Sjimharris 295230557Sjimharris# if NETINET6 296230557Sjimharris case AF_INET6: 297230557Sjimharris addr.sin6.sin6_addr = in6addr_any; 298230557Sjimharris break; 299230557Sjimharris# endif /* NETINET6 */ 300230557Sjimharris } 301230557Sjimharris } 302230557Sjimharris else 303230557Sjimharris *at = '\0'; 304230557Sjimharris 305230557Sjimharris if (isascii(*colon) && isdigit(*colon)) 306230557Sjimharris port = htons((unsigned short) atoi(colon)); 307230557Sjimharris else 308230557Sjimharris { 309230557Sjimharris# ifdef NO_GETSERVBYNAME 310230557Sjimharris smi_log(SMI_LOG_ERR, "%s: invalid port number %s", 311230557Sjimharris name, colon); 312230557Sjimharris return INVALID_SOCKET; 313230557Sjimharris# else /* NO_GETSERVBYNAME */ 314230557Sjimharris register struct servent *sp; 315230557Sjimharris 316230557Sjimharris sp = getservbyname(colon, "tcp"); 317230557Sjimharris if (sp == NULL) 318230557Sjimharris { 319230557Sjimharris smi_log(SMI_LOG_ERR, 320230557Sjimharris "%s: unknown port name %s", 321230557Sjimharris name, colon); 322230557Sjimharris return INVALID_SOCKET; 323230557Sjimharris } 324230557Sjimharris port = sp->s_port; 325230557Sjimharris# endif /* NO_GETSERVBYNAME */ 326230557Sjimharris } 327230557Sjimharris if (at != NULL) 328230557Sjimharris { 329230557Sjimharris *at++ = '@'; 330230557Sjimharris if (*at == '[') 331230557Sjimharris { 332230557Sjimharris char *end; 333230557Sjimharris 334230557Sjimharris end = strchr(at, ']'); 335230557Sjimharris if (end != NULL) 336230557Sjimharris { 337230557Sjimharris bool found = false; 338230557Sjimharris# if NETINET 339230557Sjimharris unsigned long hid = INADDR_NONE; 340230557Sjimharris# endif /* NETINET */ 341230557Sjimharris# if NETINET6 342230557Sjimharris struct sockaddr_in6 hid6; 343230557Sjimharris# endif /* NETINET6 */ 344230557Sjimharris 345230557Sjimharris *end = '\0'; 346230557Sjimharris# if NETINET 347230557Sjimharris if (addr.sa.sa_family == AF_INET && 348230557Sjimharris (hid = inet_addr(&at[1])) != INADDR_NONE) 349230557Sjimharris { 350230557Sjimharris addr.sin.sin_addr.s_addr = hid; 351230557Sjimharris addr.sin.sin_port = port; 352230557Sjimharris found = true; 353230557Sjimharris } 354230557Sjimharris# endif /* NETINET */ 355230557Sjimharris# if NETINET6 356230557Sjimharris (void) memset(&hid6, '\0', sizeof hid6); 357230557Sjimharris if (addr.sa.sa_family == AF_INET6 && 358230557Sjimharris mi_inet_pton(AF_INET6, &at[1], 359230557Sjimharris &hid6.sin6_addr) == 1) 360230557Sjimharris { 361230557Sjimharris addr.sin6.sin6_addr = hid6.sin6_addr; 362230557Sjimharris addr.sin6.sin6_port = port; 363230557Sjimharris found = true; 364230557Sjimharris } 365230557Sjimharris# endif /* NETINET6 */ 366230557Sjimharris *end = ']'; 367230557Sjimharris if (!found) 368230557Sjimharris { 369230557Sjimharris smi_log(SMI_LOG_ERR, 370230557Sjimharris "%s: Invalid numeric domain spec \"%s\"", 371230557Sjimharris name, at); 372230557Sjimharris return INVALID_SOCKET; 373230557Sjimharris } 374230557Sjimharris } 375230557Sjimharris else 376230557Sjimharris { 377230557Sjimharris smi_log(SMI_LOG_ERR, 378230557Sjimharris "%s: Invalid numeric domain spec \"%s\"", 379230557Sjimharris name, at); 380230557Sjimharris return INVALID_SOCKET; 381230557Sjimharris } 382230557Sjimharris } 383230557Sjimharris else 384230557Sjimharris { 385230557Sjimharris struct hostent *hp = NULL; 386230557Sjimharris 387230557Sjimharris hp = mi_gethostbyname(at, addr.sa.sa_family); 388230557Sjimharris if (hp == NULL) 389230557Sjimharris { 390230557Sjimharris smi_log(SMI_LOG_ERR, 391230557Sjimharris "%s: Unknown host name %s", 392230557Sjimharris name, at); 393230557Sjimharris return INVALID_SOCKET; 394230557Sjimharris } 395230557Sjimharris addr.sa.sa_family = hp->h_addrtype; 396230557Sjimharris switch (hp->h_addrtype) 397230557Sjimharris { 398230557Sjimharris# if NETINET 399230557Sjimharris case AF_INET: 400230557Sjimharris (void) memmove(&addr.sin.sin_addr, 401230557Sjimharris hp->h_addr, 402230557Sjimharris INADDRSZ); 403230557Sjimharris addr.sin.sin_port = port; 404230557Sjimharris break; 405230557Sjimharris# endif /* NETINET */ 406230557Sjimharris 407230557Sjimharris# if NETINET6 408230557Sjimharris case AF_INET6: 409230557Sjimharris (void) memmove(&addr.sin6.sin6_addr, 410230557Sjimharris hp->h_addr, 411230557Sjimharris IN6ADDRSZ); 412230557Sjimharris addr.sin6.sin6_port = port; 413230557Sjimharris break; 414230557Sjimharris# endif /* NETINET6 */ 415230557Sjimharris 416230557Sjimharris default: 417230557Sjimharris smi_log(SMI_LOG_ERR, 418230557Sjimharris "%s: Unknown protocol for %s (%d)", 419230557Sjimharris name, at, hp->h_addrtype); 420230557Sjimharris return INVALID_SOCKET; 421230557Sjimharris } 422230557Sjimharris# if NETINET6 423230557Sjimharris freehostent(hp); 424230557Sjimharris# endif /* NETINET6 */ 425230557Sjimharris } 426230557Sjimharris } 427230557Sjimharris else 428230557Sjimharris { 429230557Sjimharris switch (addr.sa.sa_family) 430230557Sjimharris { 431230557Sjimharris# if NETINET 432230557Sjimharris case AF_INET: 433230557Sjimharris addr.sin.sin_port = port; 434230557Sjimharris break; 435230557Sjimharris# endif /* NETINET */ 436230557Sjimharris# if NETINET6 437230557Sjimharris case AF_INET6: 438230557Sjimharris addr.sin6.sin6_port = port; 439230557Sjimharris break; 440230557Sjimharris# endif /* NETINET6 */ 441230557Sjimharris } 442230557Sjimharris } 443230557Sjimharris } 444230557Sjimharris#endif /* NETINET || NETINET6 */ 445230557Sjimharris 446230557Sjimharris sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 447230557Sjimharris if (!ValidSocket(sock)) 448230557Sjimharris { 449230557Sjimharris smi_log(SMI_LOG_ERR, 450230557Sjimharris "%s: Unable to create new socket: %s", 451230557Sjimharris name, sm_errstring(errno)); 452230557Sjimharris return INVALID_SOCKET; 453230557Sjimharris } 454230557Sjimharris 455230557Sjimharris if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 || 456230557Sjimharris fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1) 457230557Sjimharris { 458230557Sjimharris smi_log(SMI_LOG_ERR, 459230557Sjimharris "%s: Unable to set close-on-exec: %s", name, 460230557Sjimharris sm_errstring(errno)); 461230557Sjimharris (void) closesocket(sock); 462230557Sjimharris return INVALID_SOCKET; 463230557Sjimharris } 464230557Sjimharris 465230557Sjimharris if ( 466230557Sjimharris#if NETUNIX 467230557Sjimharris addr.sa.sa_family != AF_UNIX && 468230557Sjimharris#endif /* NETUNIX */ 469230557Sjimharris setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 470230557Sjimharris sizeof(sockopt)) == -1) 471230557Sjimharris { 472230557Sjimharris smi_log(SMI_LOG_ERR, 473230557Sjimharris "%s: set reuseaddr failed (%s)", name, 474230557Sjimharris sm_errstring(errno)); 475230557Sjimharris (void) closesocket(sock); 476230557Sjimharris return INVALID_SOCKET; 477230557Sjimharris } 478230557Sjimharris 479230557Sjimharris#if NETUNIX 480230557Sjimharris if (addr.sa.sa_family == AF_UNIX && rmsocket) 481230557Sjimharris { 482230557Sjimharris struct stat s; 483230557Sjimharris 484230557Sjimharris if (stat(colon, &s) != 0) 485230557Sjimharris { 486230557Sjimharris if (errno != ENOENT) 487230557Sjimharris { 488230557Sjimharris smi_log(SMI_LOG_ERR, 489230557Sjimharris "%s: Unable to stat() %s: %s", 490230557Sjimharris name, colon, sm_errstring(errno)); 491230557Sjimharris (void) closesocket(sock); 492230557Sjimharris return INVALID_SOCKET; 493230557Sjimharris } 494230557Sjimharris } 495230557Sjimharris else if (!S_ISSOCK(s.st_mode)) 496230557Sjimharris { 497230557Sjimharris smi_log(SMI_LOG_ERR, 498230557Sjimharris "%s: %s is not a UNIX domain socket", 499230557Sjimharris name, colon); 500230557Sjimharris (void) closesocket(sock); 501230557Sjimharris return INVALID_SOCKET; 502230557Sjimharris } 503 else if (unlink(colon) != 0) 504 { 505 smi_log(SMI_LOG_ERR, 506 "%s: Unable to remove %s: %s", 507 name, colon, sm_errstring(errno)); 508 (void) closesocket(sock); 509 return INVALID_SOCKET; 510 } 511 } 512#endif /* NETUNIX */ 513 514 if (bind(sock, &addr.sa, L_socksize) < 0) 515 { 516 smi_log(SMI_LOG_ERR, 517 "%s: Unable to bind to port %s: %s", 518 name, conn, sm_errstring(errno)); 519 (void) closesocket(sock); 520 return INVALID_SOCKET; 521 } 522 523 if (listen(sock, backlog) < 0) 524 { 525 smi_log(SMI_LOG_ERR, 526 "%s: listen call failed: %s", name, 527 sm_errstring(errno)); 528 (void) closesocket(sock); 529 return INVALID_SOCKET; 530 } 531 532#if NETUNIX 533 if (addr.sa.sa_family == AF_UNIX && len > 0) 534 { 535 /* 536 ** Set global variable sockpath so the UNIX socket can be 537 ** unlink()ed at exit. 538 */ 539 540 sockpath = (char *) malloc(len); 541 if (sockpath != NULL) 542 (void) sm_strlcpy(sockpath, colon, len); 543 else 544 { 545 smi_log(SMI_LOG_ERR, 546 "%s: can't malloc(%d) for sockpath: %s", 547 name, (int) len, sm_errstring(errno)); 548 (void) closesocket(sock); 549 return INVALID_SOCKET; 550 } 551 } 552#endif /* NETUNIX */ 553 L_family = addr.sa.sa_family; 554 return sock; 555} 556 557#if !_FFR_WORKERS_POOL 558/* 559** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 560** 561** Parameters: 562** arg -- argument to pass to mi_handle_session() 563** 564** Returns: 565** results from mi_handle_session() 566*/ 567 568static void * 569mi_thread_handle_wrapper(arg) 570 void *arg; 571{ 572 /* 573 ** Note: on some systems this generates a compiler warning: 574 ** cast to pointer from integer of different size 575 ** You can safely ignore this warning as the result of this function 576 ** is not used anywhere. 577 */ 578 579 return (void *) mi_handle_session(arg); 580} 581#endif /* _FFR_WORKERS_POOL */ 582 583/* 584** MI_CLOSENER -- close listen socket 585** 586** Parameters: 587** none. 588** 589** Returns: 590** none. 591*/ 592 593void 594mi_closener() 595{ 596 (void) smutex_lock(&L_Mutex); 597 if (ValidSocket(listenfd)) 598 { 599#if NETUNIX 600 bool removable; 601 struct stat sockinfo; 602 struct stat fileinfo; 603 604 removable = sockpath != NULL && 605 geteuid() != 0 && 606 fstat(listenfd, &sockinfo) == 0 && 607 (S_ISFIFO(sockinfo.st_mode) 608# ifdef S_ISSOCK 609 || S_ISSOCK(sockinfo.st_mode) 610# endif /* S_ISSOCK */ 611 ); 612#endif /* NETUNIX */ 613 614 (void) closesocket(listenfd); 615 listenfd = INVALID_SOCKET; 616 617#if NETUNIX 618 /* XXX sleep() some time before doing this? */ 619 if (sockpath != NULL) 620 { 621 if (removable && 622 stat(sockpath, &fileinfo) == 0 && 623 ((fileinfo.st_dev == sockinfo.st_dev && 624 fileinfo.st_ino == sockinfo.st_ino) 625# ifdef S_ISSOCK 626 || S_ISSOCK(fileinfo.st_mode) 627# endif /* S_ISSOCK */ 628 ) 629 && 630 (S_ISFIFO(fileinfo.st_mode) 631# ifdef S_ISSOCK 632 || S_ISSOCK(fileinfo.st_mode) 633# endif /* S_ISSOCK */ 634 )) 635 (void) unlink(sockpath); 636 free(sockpath); 637 sockpath = NULL; 638 } 639#endif /* NETUNIX */ 640 } 641 (void) smutex_unlock(&L_Mutex); 642} 643 644/* 645** MI_LISTENER -- Generic listener harness 646** 647** Open up listen port 648** Wait for connections 649** 650** Parameters: 651** conn -- connection description 652** dbg -- debug level 653** smfi -- filter structure to use 654** timeout -- timeout for reads/writes 655** backlog -- listen queue backlog size 656** 657** Returns: 658** MI_SUCCESS -- Exited normally 659** (session finished or we were told to exit) 660** MI_FAILURE -- Network initialization failed. 661*/ 662 663#if BROKEN_PTHREAD_SLEEP 664 665/* 666** Solaris 2.6, perhaps others, gets an internal threads library panic 667** when sleep() is used: 668** 669** thread_create() failed, returned 11 (EINVAL) 670** co_enable, thr_create() returned error = 24 671** libthread panic: co_enable failed (PID: 17793 LWP 1) 672** stacktrace: 673** ef526b10 674** ef52646c 675** ef534cbc 676** 156a4 677** 14644 678** 1413c 679** 135e0 680** 0 681*/ 682 683# define MI_SLEEP(s) \ 684{ \ 685 int rs = 0; \ 686 struct timeval st; \ 687 \ 688 st.tv_sec = (s); \ 689 st.tv_usec = 0; \ 690 if (st.tv_sec > 0) \ 691 { \ 692 for (;;) \ 693 { \ 694 rs = select(0, NULL, NULL, NULL, &st); \ 695 if (rs < 0 && errno == EINTR) \ 696 continue; \ 697 if (rs != 0) \ 698 { \ 699 smi_log(SMI_LOG_ERR, \ 700 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ 701 rs, errno); \ 702 } \ 703 break; \ 704 } \ 705 } \ 706} 707#else /* BROKEN_PTHREAD_SLEEP */ 708# define MI_SLEEP(s) sleep((s)) 709#endif /* BROKEN_PTHREAD_SLEEP */ 710 711int 712mi_listener(conn, dbg, smfi, timeout, backlog) 713 char *conn; 714 int dbg; 715 smfiDesc_ptr smfi; 716 time_t timeout; 717 int backlog; 718{ 719 socket_t connfd = INVALID_SOCKET; 720#if _FFR_DUP_FD 721 socket_t dupfd = INVALID_SOCKET; 722#endif /* _FFR_DUP_FD */ 723 int sockopt = 1; 724 int r, mistop; 725 int ret = MI_SUCCESS; 726 int mcnt = 0; /* error count for malloc() failures */ 727 int tcnt = 0; /* error count for thread_create() failures */ 728 int acnt = 0; /* error count for accept() failures */ 729 int scnt = 0; /* error count for select() failures */ 730 int save_errno = 0; 731#if !_FFR_WORKERS_POOL 732 sthread_t thread_id; 733#endif /* !_FFR_WORKERS_POOL */ 734 _SOCK_ADDR cliaddr; 735 SOCKADDR_LEN_T clilen; 736 SMFICTX_PTR ctx; 737 FD_RD_VAR(rds, excs); 738 struct timeval chktime; 739 740 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE) 741 return MI_FAILURE; 742 743#if _FFR_WORKERS_POOL 744 if (mi_pool_controller_init() == MI_FAILURE) 745 return MI_FAILURE; 746#endif /* _FFR_WORKERS_POOL */ 747 748 clilen = L_socksize; 749 while ((mistop = mi_stop()) == MILTER_CONT) 750 { 751 (void) smutex_lock(&L_Mutex); 752 if (!ValidSocket(listenfd)) 753 { 754 ret = MI_FAILURE; 755 smi_log(SMI_LOG_ERR, 756 "%s: listenfd=%d corrupted, terminating, errno=%d", 757 smfi->xxfi_name, listenfd, errno); 758 (void) smutex_unlock(&L_Mutex); 759 break; 760 } 761 762 /* select on interface ports */ 763 FD_RD_INIT(listenfd, rds, excs); 764 chktime.tv_sec = MI_CHK_TIME; 765 chktime.tv_usec = 0; 766 r = FD_RD_READY(listenfd, rds, excs, &chktime); 767 if (r == 0) /* timeout */ 768 { 769 (void) smutex_unlock(&L_Mutex); 770 continue; /* just check mi_stop() */ 771 } 772 if (r < 0) 773 { 774 save_errno = errno; 775 (void) smutex_unlock(&L_Mutex); 776 if (save_errno == EINTR) 777 continue; 778 scnt++; 779 smi_log(SMI_LOG_ERR, 780 "%s: %s() failed (%s), %s", 781 smfi->xxfi_name, MI_POLLSELECT, 782 sm_errstring(save_errno), 783 scnt >= MAX_FAILS_S ? "abort" : "try again"); 784 MI_SLEEP(scnt); 785 if (scnt >= MAX_FAILS_S) 786 { 787 ret = MI_FAILURE; 788 break; 789 } 790 continue; 791 } 792 if (!FD_IS_RD_RDY(listenfd, rds, excs)) 793 { 794 /* some error: just stop for now... */ 795 ret = MI_FAILURE; 796 (void) smutex_unlock(&L_Mutex); 797 smi_log(SMI_LOG_ERR, 798 "%s: %s() returned exception for socket, abort", 799 smfi->xxfi_name, MI_POLLSELECT); 800 break; 801 } 802 scnt = 0; /* reset error counter for select() */ 803 804 (void) memset(&cliaddr, '\0', sizeof cliaddr); 805 connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 806 &clilen); 807 save_errno = errno; 808 (void) smutex_unlock(&L_Mutex); 809 810 /* 811 ** If remote side closes before accept() finishes, 812 ** sockaddr might not be fully filled in. 813 */ 814 815 if (ValidSocket(connfd) && 816 (clilen == 0 || 817# ifdef BSD4_4_SOCKADDR 818 cliaddr.sa.sa_len == 0 || 819# endif /* BSD4_4_SOCKADDR */ 820 cliaddr.sa.sa_family != L_family)) 821 { 822 (void) closesocket(connfd); 823 connfd = INVALID_SOCKET; 824 save_errno = EINVAL; 825 } 826 827 /* check if acceptable for select() */ 828 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd)) 829 { 830 (void) closesocket(connfd); 831 connfd = INVALID_SOCKET; 832 save_errno = ERANGE; 833 } 834 835 if (!ValidSocket(connfd)) 836 { 837 if (save_errno == EINTR 838#ifdef EAGAIN 839 || save_errno == EAGAIN 840#endif /* EAGAIN */ 841#ifdef ECONNABORTED 842 || save_errno == ECONNABORTED 843#endif /* ECONNABORTED */ 844#ifdef EMFILE 845 || save_errno == EMFILE 846#endif /* EMFILE */ 847#ifdef ENFILE 848 || save_errno == ENFILE 849#endif /* ENFILE */ 850#ifdef ENOBUFS 851 || save_errno == ENOBUFS 852#endif /* ENOBUFS */ 853#ifdef ENOMEM 854 || save_errno == ENOMEM 855#endif /* ENOMEM */ 856#ifdef ENOSR 857 || save_errno == ENOSR 858#endif /* ENOSR */ 859#ifdef EWOULDBLOCK 860 || save_errno == EWOULDBLOCK 861#endif /* EWOULDBLOCK */ 862 ) 863 continue; 864 acnt++; 865 smi_log(SMI_LOG_ERR, 866 "%s: accept() returned invalid socket (%s), %s", 867 smfi->xxfi_name, sm_errstring(save_errno), 868 acnt >= MAX_FAILS_A ? "abort" : "try again"); 869 MI_SLEEP(acnt); 870 if (acnt >= MAX_FAILS_A) 871 { 872 ret = MI_FAILURE; 873 break; 874 } 875 continue; 876 } 877 acnt = 0; /* reset error counter for accept() */ 878#if _FFR_DUP_FD 879 dupfd = fcntl(connfd, F_DUPFD, 256); 880 if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd)) 881 { 882 close(connfd); 883 connfd = dupfd; 884 dupfd = INVALID_SOCKET; 885 } 886#endif /* _FFR_DUP_FD */ 887 888 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 889 (void *) &sockopt, sizeof sockopt) < 0) 890 { 891 smi_log(SMI_LOG_WARN, 892 "%s: set keepalive failed (%s)", 893 smfi->xxfi_name, sm_errstring(errno)); 894 /* XXX: continue? */ 895 } 896 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 897 { 898 (void) closesocket(connfd); 899 mcnt++; 900 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s", 901 smfi->xxfi_name, sm_errstring(save_errno), 902 mcnt >= MAX_FAILS_M ? "abort" : "try again"); 903 MI_SLEEP(mcnt); 904 if (mcnt >= MAX_FAILS_M) 905 { 906 ret = MI_FAILURE; 907 break; 908 } 909 continue; 910 } 911 mcnt = 0; /* reset error counter for malloc() */ 912 (void) memset(ctx, '\0', sizeof *ctx); 913 ctx->ctx_sd = connfd; 914 ctx->ctx_dbg = dbg; 915 ctx->ctx_timeout = timeout; 916 ctx->ctx_smfi = smfi; 917 if (smfi->xxfi_connect == NULL) 918 ctx->ctx_pflags |= SMFIP_NOCONNECT; 919 if (smfi->xxfi_helo == NULL) 920 ctx->ctx_pflags |= SMFIP_NOHELO; 921 if (smfi->xxfi_envfrom == NULL) 922 ctx->ctx_pflags |= SMFIP_NOMAIL; 923 if (smfi->xxfi_envrcpt == NULL) 924 ctx->ctx_pflags |= SMFIP_NORCPT; 925 if (smfi->xxfi_header == NULL) 926 ctx->ctx_pflags |= SMFIP_NOHDRS; 927 if (smfi->xxfi_eoh == NULL) 928 ctx->ctx_pflags |= SMFIP_NOEOH; 929 if (smfi->xxfi_body == NULL) 930 ctx->ctx_pflags |= SMFIP_NOBODY; 931 if (smfi->xxfi_version <= 3 || smfi->xxfi_data == NULL) 932 ctx->ctx_pflags |= SMFIP_NODATA; 933 if (smfi->xxfi_version <= 2 || smfi->xxfi_unknown == NULL) 934 ctx->ctx_pflags |= SMFIP_NOUNKNOWN; 935 936#if _FFR_WORKERS_POOL 937# define LOG_CRT_FAIL "%s: mi_start_session() failed: %d, %s" 938 if ((r = mi_start_session(ctx)) != MI_SUCCESS) 939#else /* _FFR_WORKERS_POOL */ 940# define LOG_CRT_FAIL "%s: thread_create() failed: %d, %s" 941 if ((r = thread_create(&thread_id, 942 mi_thread_handle_wrapper, 943 (void *) ctx)) != 0) 944#endif /* _FFR_WORKERS_POOL */ 945 { 946 tcnt++; 947 smi_log(SMI_LOG_ERR, 948 LOG_CRT_FAIL, 949 smfi->xxfi_name, r, 950 tcnt >= MAX_FAILS_T ? "abort" : "try again"); 951 MI_SLEEP(tcnt); 952 (void) closesocket(connfd); 953 free(ctx); 954 if (tcnt >= MAX_FAILS_T) 955 { 956 ret = MI_FAILURE; 957 break; 958 } 959 continue; 960 } 961 tcnt = 0; 962 } 963 if (ret != MI_SUCCESS) 964 mi_stop_milters(MILTER_ABRT); 965 else 966 { 967 if (mistop != MILTER_CONT) 968 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d", 969 smfi->xxfi_name, mistop); 970 mi_closener(); 971 } 972 (void) smutex_destroy(&L_Mutex); 973 return ret; 974} 975