164562Sgshapiro/* 2261194Sgshapiro * Copyright (c) 1999-2007 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12266527SgshapiroSM_RCSID("@(#)$Id: listener.c,v 8.127 2013-11-22 20:51:36 ca Exp $") 1364562Sgshapiro 1464562Sgshapiro/* 1564562Sgshapiro** listener.c -- threaded network listener 1664562Sgshapiro*/ 1764562Sgshapiro 1864562Sgshapiro#include "libmilter.h" 1990792Sgshapiro#include <sm/errstring.h> 2064562Sgshapiro 21125820Sgshapiro#include <sys/types.h> 22125820Sgshapiro#include <sys/stat.h> 2364562Sgshapiro 24125820Sgshapiro 2564562Sgshapiro# if NETINET || NETINET6 2664562Sgshapiro# include <arpa/inet.h> 27363466Sgshapiro# endif 28168515Sgshapiro# if SM_CONF_POLL 29168515Sgshapiro# undef SM_FD_OK_SELECT 30168515Sgshapiro# define SM_FD_OK_SELECT(fd) true 31363466Sgshapiro# endif 3290792Sgshapiro 3390792Sgshapirostatic smutex_t L_Mutex; 3498121Sgshapirostatic int L_family; 3598121Sgshapirostatic SOCKADDR_LEN_T L_socksize; 3698121Sgshapirostatic socket_t listenfd = INVALID_SOCKET; 3790792Sgshapiro 38125820Sgshapirostatic socket_t mi_milteropen __P((char *, int, bool, char *)); 39168515Sgshapiro#if !_FFR_WORKERS_POOL 40141858Sgshapirostatic void *mi_thread_handle_wrapper __P((void *)); 41363466Sgshapiro#endif 4298121Sgshapiro 4390792Sgshapiro/* 4498121Sgshapiro** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet 4598121Sgshapiro** 46125820Sgshapiro** Parameters: 4798121Sgshapiro** conn -- connection description 4898121Sgshapiro** backlog -- listen backlog 49125820Sgshapiro** dbg -- debug level 50125820Sgshapiro** rmsocket -- if true, try to unlink() the socket first 51132943Sgshapiro** (UNIX domain sockets only) 5298121Sgshapiro** smfi -- filter structure to use 5398121Sgshapiro** 54125820Sgshapiro** Return value: 55125820Sgshapiro** MI_SUCCESS/MI_FAILURE 5698121Sgshapiro*/ 5798121Sgshapiro 5898121Sgshapiroint 59125820Sgshapiromi_opensocket(conn, backlog, dbg, rmsocket, smfi) 6098121Sgshapiro char *conn; 6198121Sgshapiro int backlog; 6298121Sgshapiro int dbg; 63125820Sgshapiro bool rmsocket; 6498121Sgshapiro smfiDesc_ptr smfi; 6598121Sgshapiro{ 6698121Sgshapiro if (smfi == NULL || conn == NULL) 6798121Sgshapiro return MI_FAILURE; 6898121Sgshapiro 6998121Sgshapiro if (ValidSocket(listenfd)) 7098121Sgshapiro return MI_SUCCESS; 7198121Sgshapiro 7298121Sgshapiro if (dbg > 0) 7398121Sgshapiro { 7498121Sgshapiro smi_log(SMI_LOG_DEBUG, 7598121Sgshapiro "%s: Opening listen socket on conn %s", 7698121Sgshapiro smfi->xxfi_name, conn); 7798121Sgshapiro } 7898121Sgshapiro (void) smutex_init(&L_Mutex); 7998121Sgshapiro (void) smutex_lock(&L_Mutex); 80125820Sgshapiro listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name); 8198121Sgshapiro if (!ValidSocket(listenfd)) 8298121Sgshapiro { 8398121Sgshapiro smi_log(SMI_LOG_FATAL, 8498121Sgshapiro "%s: Unable to create listening socket on conn %s", 8598121Sgshapiro smfi->xxfi_name, conn); 8698121Sgshapiro (void) smutex_unlock(&L_Mutex); 8798121Sgshapiro return MI_FAILURE; 8898121Sgshapiro } 89110560Sgshapiro if (!SM_FD_OK_SELECT(listenfd)) 90110560Sgshapiro { 91110560Sgshapiro smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 92110560Sgshapiro smfi->xxfi_name, listenfd, FD_SETSIZE); 93110560Sgshapiro (void) smutex_unlock(&L_Mutex); 94110560Sgshapiro return MI_FAILURE; 95110560Sgshapiro } 96141858Sgshapiro (void) smutex_unlock(&L_Mutex); 9798121Sgshapiro return MI_SUCCESS; 9898121Sgshapiro} 9998121Sgshapiro 10098121Sgshapiro/* 10164562Sgshapiro** MI_MILTEROPEN -- setup socket to listen on 10264562Sgshapiro** 10364562Sgshapiro** Parameters: 10464562Sgshapiro** conn -- connection description 10564562Sgshapiro** backlog -- listen backlog 106125820Sgshapiro** rmsocket -- if true, try to unlink() the socket first 107125820Sgshapiro** (UNIX domain sockets only) 10873188Sgshapiro** name -- name for logging 10964562Sgshapiro** 11064562Sgshapiro** Returns: 11164562Sgshapiro** socket upon success, error code otherwise. 11290792Sgshapiro** 11390792Sgshapiro** Side effect: 11490792Sgshapiro** sets sockpath if UNIX socket. 11564562Sgshapiro*/ 11664562Sgshapiro 11790792Sgshapiro#if NETUNIX 11890792Sgshapirostatic char *sockpath = NULL; 119363466Sgshapiro#endif 12090792Sgshapiro 12166494Sgshapirostatic socket_t 122125820Sgshapiromi_milteropen(conn, backlog, rmsocket, name) 12364562Sgshapiro char *conn; 12464562Sgshapiro int backlog; 125125820Sgshapiro bool rmsocket; 12664562Sgshapiro char *name; 12764562Sgshapiro{ 12866494Sgshapiro socket_t sock; 12964562Sgshapiro int sockopt = 1; 13098121Sgshapiro int fdflags; 13190792Sgshapiro size_t len = 0; 13264562Sgshapiro char *p; 13364562Sgshapiro char *colon; 13464562Sgshapiro char *at; 13564562Sgshapiro SOCKADDR addr; 13664562Sgshapiro 13764562Sgshapiro if (conn == NULL || conn[0] == '\0') 13864562Sgshapiro { 13964562Sgshapiro smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", 14064562Sgshapiro name); 14166494Sgshapiro return INVALID_SOCKET; 14264562Sgshapiro } 14364562Sgshapiro (void) memset(&addr, '\0', sizeof addr); 14464562Sgshapiro 14564562Sgshapiro /* protocol:filename or protocol:port@host */ 14664562Sgshapiro p = conn; 14764562Sgshapiro colon = strchr(p, ':'); 14864562Sgshapiro if (colon != NULL) 14964562Sgshapiro { 15064562Sgshapiro *colon = '\0'; 15164562Sgshapiro 15294334Sgshapiro if (*p == '\0') 15364562Sgshapiro { 15464562Sgshapiro#if NETUNIX 15564562Sgshapiro /* default to AF_UNIX */ 15694334Sgshapiro addr.sa.sa_family = AF_UNIX; 15798121Sgshapiro L_socksize = sizeof (struct sockaddr_un); 15864562Sgshapiro#else /* NETUNIX */ 15964562Sgshapiro# if NETINET 16064562Sgshapiro /* default to AF_INET */ 16164562Sgshapiro addr.sa.sa_family = AF_INET; 16298121Sgshapiro L_socksize = sizeof addr.sin; 16364562Sgshapiro# else /* NETINET */ 16464562Sgshapiro# if NETINET6 16564562Sgshapiro /* default to AF_INET6 */ 16664562Sgshapiro addr.sa.sa_family = AF_INET6; 16798121Sgshapiro L_socksize = sizeof addr.sin6; 16864562Sgshapiro# else /* NETINET6 */ 16964562Sgshapiro /* no protocols available */ 17064562Sgshapiro smi_log(SMI_LOG_ERR, 17164562Sgshapiro "%s: no valid socket protocols available", 17264562Sgshapiro name); 17366494Sgshapiro return INVALID_SOCKET; 17464562Sgshapiro# endif /* NETINET6 */ 17564562Sgshapiro# endif /* NETINET */ 17664562Sgshapiro#endif /* NETUNIX */ 17764562Sgshapiro } 17864562Sgshapiro#if NETUNIX 17964562Sgshapiro else if (strcasecmp(p, "unix") == 0 || 18064562Sgshapiro strcasecmp(p, "local") == 0) 18164562Sgshapiro { 18264562Sgshapiro addr.sa.sa_family = AF_UNIX; 18398121Sgshapiro L_socksize = sizeof (struct sockaddr_un); 18464562Sgshapiro } 18564562Sgshapiro#endif /* NETUNIX */ 18664562Sgshapiro#if NETINET 18764562Sgshapiro else if (strcasecmp(p, "inet") == 0) 18864562Sgshapiro { 18964562Sgshapiro addr.sa.sa_family = AF_INET; 19098121Sgshapiro L_socksize = sizeof addr.sin; 19164562Sgshapiro } 19264562Sgshapiro#endif /* NETINET */ 19364562Sgshapiro#if NETINET6 19464562Sgshapiro else if (strcasecmp(p, "inet6") == 0) 19564562Sgshapiro { 19664562Sgshapiro addr.sa.sa_family = AF_INET6; 19798121Sgshapiro L_socksize = sizeof addr.sin6; 19864562Sgshapiro } 19964562Sgshapiro#endif /* NETINET6 */ 20064562Sgshapiro else 20164562Sgshapiro { 20264562Sgshapiro smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 20364562Sgshapiro name, p); 20466494Sgshapiro return INVALID_SOCKET; 20564562Sgshapiro } 20664562Sgshapiro *colon++ = ':'; 20764562Sgshapiro } 20864562Sgshapiro else 20964562Sgshapiro { 21064562Sgshapiro colon = p; 21164562Sgshapiro#if NETUNIX 21264562Sgshapiro /* default to AF_UNIX */ 21394334Sgshapiro addr.sa.sa_family = AF_UNIX; 21498121Sgshapiro L_socksize = sizeof (struct sockaddr_un); 21564562Sgshapiro#else /* NETUNIX */ 21664562Sgshapiro# if NETINET 21764562Sgshapiro /* default to AF_INET */ 21864562Sgshapiro addr.sa.sa_family = AF_INET; 21998121Sgshapiro L_socksize = sizeof addr.sin; 22064562Sgshapiro# else /* NETINET */ 22164562Sgshapiro# if NETINET6 22264562Sgshapiro /* default to AF_INET6 */ 22364562Sgshapiro addr.sa.sa_family = AF_INET6; 22498121Sgshapiro L_socksize = sizeof addr.sin6; 22564562Sgshapiro# else /* NETINET6 */ 22664562Sgshapiro smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 22764562Sgshapiro name, p); 22866494Sgshapiro return INVALID_SOCKET; 22964562Sgshapiro# endif /* NETINET6 */ 23064562Sgshapiro# endif /* NETINET */ 23164562Sgshapiro#endif /* NETUNIX */ 23264562Sgshapiro } 23364562Sgshapiro 23464562Sgshapiro#if NETUNIX 23564562Sgshapiro if (addr.sa.sa_family == AF_UNIX) 23664562Sgshapiro { 23764562Sgshapiro# if 0 23864562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 23964562Sgshapiro# endif /* 0 */ 24064562Sgshapiro 24164562Sgshapiro at = colon; 24290792Sgshapiro len = strlen(colon) + 1; 24390792Sgshapiro if (len >= sizeof addr.sunix.sun_path) 24464562Sgshapiro { 24564562Sgshapiro errno = EINVAL; 24664562Sgshapiro smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", 24764562Sgshapiro name, colon); 24866494Sgshapiro return INVALID_SOCKET; 24964562Sgshapiro } 25090792Sgshapiro (void) sm_strlcpy(addr.sunix.sun_path, colon, 25190792Sgshapiro sizeof addr.sunix.sun_path); 25264562Sgshapiro# if 0 25364562Sgshapiro errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 25464562Sgshapiro S_IRUSR|S_IWUSR, NULL); 25564562Sgshapiro 25664562Sgshapiro /* if not safe, don't create */ 25764562Sgshapiro if (errno != 0) 25864562Sgshapiro { 25964562Sgshapiro smi_log(SMI_LOG_ERR, 26064562Sgshapiro "%s: UNIX socket name %s unsafe", 26164562Sgshapiro name, colon); 26266494Sgshapiro return INVALID_SOCKET; 26364562Sgshapiro } 26464562Sgshapiro# endif /* 0 */ 26564562Sgshapiro } 26664562Sgshapiro#endif /* NETUNIX */ 26764562Sgshapiro 26864562Sgshapiro#if NETINET || NETINET6 26964562Sgshapiro if ( 27064562Sgshapiro# if NETINET 27164562Sgshapiro addr.sa.sa_family == AF_INET 272363466Sgshapiro# endif 27364562Sgshapiro# if NETINET && NETINET6 27464562Sgshapiro || 275363466Sgshapiro# endif 27664562Sgshapiro# if NETINET6 27764562Sgshapiro addr.sa.sa_family == AF_INET6 278363466Sgshapiro# endif 27964562Sgshapiro ) 28064562Sgshapiro { 28190792Sgshapiro unsigned short port; 28264562Sgshapiro 28364562Sgshapiro /* Parse port@host */ 28464562Sgshapiro at = strchr(colon, '@'); 28564562Sgshapiro if (at == NULL) 28664562Sgshapiro { 28764562Sgshapiro switch (addr.sa.sa_family) 28864562Sgshapiro { 28964562Sgshapiro# if NETINET 29064562Sgshapiro case AF_INET: 29164562Sgshapiro addr.sin.sin_addr.s_addr = INADDR_ANY; 29264562Sgshapiro break; 293363466Sgshapiro# endif 29464562Sgshapiro 29564562Sgshapiro# if NETINET6 29664562Sgshapiro case AF_INET6: 29764562Sgshapiro addr.sin6.sin6_addr = in6addr_any; 29864562Sgshapiro break; 299363466Sgshapiro# endif 30064562Sgshapiro } 30164562Sgshapiro } 30264562Sgshapiro else 30364562Sgshapiro *at = '\0'; 30464562Sgshapiro 30564562Sgshapiro if (isascii(*colon) && isdigit(*colon)) 30690792Sgshapiro port = htons((unsigned short) atoi(colon)); 30764562Sgshapiro else 30864562Sgshapiro { 30964562Sgshapiro# ifdef NO_GETSERVBYNAME 31064562Sgshapiro smi_log(SMI_LOG_ERR, "%s: invalid port number %s", 31164562Sgshapiro name, colon); 31266494Sgshapiro return INVALID_SOCKET; 31364562Sgshapiro# else /* NO_GETSERVBYNAME */ 31464562Sgshapiro register struct servent *sp; 31564562Sgshapiro 31664562Sgshapiro sp = getservbyname(colon, "tcp"); 31764562Sgshapiro if (sp == NULL) 31864562Sgshapiro { 31964562Sgshapiro smi_log(SMI_LOG_ERR, 32064562Sgshapiro "%s: unknown port name %s", 32164562Sgshapiro name, colon); 32266494Sgshapiro return INVALID_SOCKET; 32364562Sgshapiro } 32464562Sgshapiro port = sp->s_port; 32564562Sgshapiro# endif /* NO_GETSERVBYNAME */ 32664562Sgshapiro } 32764562Sgshapiro if (at != NULL) 32864562Sgshapiro { 32964562Sgshapiro *at++ = '@'; 33064562Sgshapiro if (*at == '[') 33164562Sgshapiro { 33264562Sgshapiro char *end; 33364562Sgshapiro 33464562Sgshapiro end = strchr(at, ']'); 33564562Sgshapiro if (end != NULL) 33664562Sgshapiro { 33790792Sgshapiro bool found = false; 33864562Sgshapiro# if NETINET 33964562Sgshapiro unsigned long hid = INADDR_NONE; 340363466Sgshapiro# endif 34164562Sgshapiro# if NETINET6 34264562Sgshapiro struct sockaddr_in6 hid6; 343363466Sgshapiro# endif 34464562Sgshapiro 34564562Sgshapiro *end = '\0'; 34664562Sgshapiro# if NETINET 34764562Sgshapiro if (addr.sa.sa_family == AF_INET && 34890792Sgshapiro (hid = inet_addr(&at[1])) != INADDR_NONE) 34964562Sgshapiro { 35064562Sgshapiro addr.sin.sin_addr.s_addr = hid; 35164562Sgshapiro addr.sin.sin_port = port; 35290792Sgshapiro found = true; 35364562Sgshapiro } 35464562Sgshapiro# endif /* NETINET */ 35564562Sgshapiro# if NETINET6 35664562Sgshapiro (void) memset(&hid6, '\0', sizeof hid6); 35764562Sgshapiro if (addr.sa.sa_family == AF_INET6 && 35890792Sgshapiro mi_inet_pton(AF_INET6, &at[1], 35990792Sgshapiro &hid6.sin6_addr) == 1) 36064562Sgshapiro { 36164562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 36264562Sgshapiro addr.sin6.sin6_port = port; 36390792Sgshapiro found = true; 36464562Sgshapiro } 36564562Sgshapiro# endif /* NETINET6 */ 36664562Sgshapiro *end = ']'; 36764562Sgshapiro if (!found) 36864562Sgshapiro { 36964562Sgshapiro smi_log(SMI_LOG_ERR, 37064562Sgshapiro "%s: Invalid numeric domain spec \"%s\"", 37164562Sgshapiro name, at); 37266494Sgshapiro return INVALID_SOCKET; 37364562Sgshapiro } 37464562Sgshapiro } 37564562Sgshapiro else 37664562Sgshapiro { 37764562Sgshapiro smi_log(SMI_LOG_ERR, 37864562Sgshapiro "%s: Invalid numeric domain spec \"%s\"", 37964562Sgshapiro name, at); 38066494Sgshapiro return INVALID_SOCKET; 38164562Sgshapiro } 38264562Sgshapiro } 38364562Sgshapiro else 38464562Sgshapiro { 38571345Sgshapiro struct hostent *hp = NULL; 38671345Sgshapiro 38764562Sgshapiro hp = mi_gethostbyname(at, addr.sa.sa_family); 38864562Sgshapiro if (hp == NULL) 38964562Sgshapiro { 39064562Sgshapiro smi_log(SMI_LOG_ERR, 39164562Sgshapiro "%s: Unknown host name %s", 39264562Sgshapiro name, at); 39366494Sgshapiro return INVALID_SOCKET; 39464562Sgshapiro } 39564562Sgshapiro addr.sa.sa_family = hp->h_addrtype; 39664562Sgshapiro switch (hp->h_addrtype) 39764562Sgshapiro { 39864562Sgshapiro# if NETINET 39964562Sgshapiro case AF_INET: 400120256Sgshapiro (void) memmove(&addr.sin.sin_addr, 401120256Sgshapiro hp->h_addr, 402120256Sgshapiro INADDRSZ); 40364562Sgshapiro addr.sin.sin_port = port; 40464562Sgshapiro break; 40564562Sgshapiro# endif /* NETINET */ 40664562Sgshapiro 40764562Sgshapiro# if NETINET6 40864562Sgshapiro case AF_INET6: 409120256Sgshapiro (void) memmove(&addr.sin6.sin6_addr, 410120256Sgshapiro hp->h_addr, 411120256Sgshapiro IN6ADDRSZ); 41264562Sgshapiro addr.sin6.sin6_port = port; 41364562Sgshapiro break; 41464562Sgshapiro# endif /* NETINET6 */ 41564562Sgshapiro 41664562Sgshapiro default: 41764562Sgshapiro smi_log(SMI_LOG_ERR, 41864562Sgshapiro "%s: Unknown protocol for %s (%d)", 41964562Sgshapiro name, at, hp->h_addrtype); 42066494Sgshapiro return INVALID_SOCKET; 42164562Sgshapiro } 42290792Sgshapiro# if NETINET6 42371345Sgshapiro freehostent(hp); 424363466Sgshapiro# endif 42564562Sgshapiro } 42664562Sgshapiro } 42764562Sgshapiro else 42864562Sgshapiro { 42964562Sgshapiro switch (addr.sa.sa_family) 43064562Sgshapiro { 43164562Sgshapiro# if NETINET 43264562Sgshapiro case AF_INET: 43364562Sgshapiro addr.sin.sin_port = port; 43464562Sgshapiro break; 435363466Sgshapiro# endif 43664562Sgshapiro# if NETINET6 43764562Sgshapiro case AF_INET6: 43864562Sgshapiro addr.sin6.sin6_port = port; 43964562Sgshapiro break; 440363466Sgshapiro# endif 44164562Sgshapiro } 44264562Sgshapiro } 44364562Sgshapiro } 44464562Sgshapiro#endif /* NETINET || NETINET6 */ 44564562Sgshapiro 44664562Sgshapiro sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 44764562Sgshapiro if (!ValidSocket(sock)) 44864562Sgshapiro { 44964562Sgshapiro smi_log(SMI_LOG_ERR, 45064562Sgshapiro "%s: Unable to create new socket: %s", 45190792Sgshapiro name, sm_errstring(errno)); 45266494Sgshapiro return INVALID_SOCKET; 45364562Sgshapiro } 45464562Sgshapiro 45598121Sgshapiro if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 || 45698121Sgshapiro fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1) 45798121Sgshapiro { 45898121Sgshapiro smi_log(SMI_LOG_ERR, 45998121Sgshapiro "%s: Unable to set close-on-exec: %s", name, 46098121Sgshapiro sm_errstring(errno)); 46198121Sgshapiro (void) closesocket(sock); 46298121Sgshapiro return INVALID_SOCKET; 46398121Sgshapiro } 46498121Sgshapiro 465157001Sgshapiro if ( 466157001Sgshapiro#if NETUNIX 467157001Sgshapiro addr.sa.sa_family != AF_UNIX && 468363466Sgshapiro#endif 469157001Sgshapiro setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 47064562Sgshapiro sizeof(sockopt)) == -1) 47164562Sgshapiro { 47264562Sgshapiro smi_log(SMI_LOG_ERR, 473157001Sgshapiro "%s: set reuseaddr failed (%s)", name, 47490792Sgshapiro sm_errstring(errno)); 47590792Sgshapiro (void) closesocket(sock); 47666494Sgshapiro return INVALID_SOCKET; 47764562Sgshapiro } 47864562Sgshapiro 479125820Sgshapiro#if NETUNIX 480125820Sgshapiro if (addr.sa.sa_family == AF_UNIX && rmsocket) 481125820Sgshapiro { 482125820Sgshapiro struct stat s; 483125820Sgshapiro 484125820Sgshapiro if (stat(colon, &s) != 0) 485125820Sgshapiro { 486125820Sgshapiro if (errno != ENOENT) 487125820Sgshapiro { 488125820Sgshapiro smi_log(SMI_LOG_ERR, 489125820Sgshapiro "%s: Unable to stat() %s: %s", 490125820Sgshapiro name, colon, sm_errstring(errno)); 491125820Sgshapiro (void) closesocket(sock); 492125820Sgshapiro return INVALID_SOCKET; 493125820Sgshapiro } 494125820Sgshapiro } 495125820Sgshapiro else if (!S_ISSOCK(s.st_mode)) 496125820Sgshapiro { 497125820Sgshapiro smi_log(SMI_LOG_ERR, 498125820Sgshapiro "%s: %s is not a UNIX domain socket", 499125820Sgshapiro name, colon); 500125820Sgshapiro (void) closesocket(sock); 501125820Sgshapiro return INVALID_SOCKET; 502125820Sgshapiro } 503125820Sgshapiro else if (unlink(colon) != 0) 504125820Sgshapiro { 505125820Sgshapiro smi_log(SMI_LOG_ERR, 506125820Sgshapiro "%s: Unable to remove %s: %s", 507125820Sgshapiro name, colon, sm_errstring(errno)); 508125820Sgshapiro (void) closesocket(sock); 509125820Sgshapiro return INVALID_SOCKET; 510125820Sgshapiro } 511125820Sgshapiro } 512125820Sgshapiro#endif /* NETUNIX */ 513125820Sgshapiro 51498121Sgshapiro if (bind(sock, &addr.sa, L_socksize) < 0) 51564562Sgshapiro { 51664562Sgshapiro smi_log(SMI_LOG_ERR, 51764562Sgshapiro "%s: Unable to bind to port %s: %s", 51890792Sgshapiro name, conn, sm_errstring(errno)); 51990792Sgshapiro (void) closesocket(sock); 52066494Sgshapiro return INVALID_SOCKET; 52164562Sgshapiro } 52264562Sgshapiro 52364562Sgshapiro if (listen(sock, backlog) < 0) 52464562Sgshapiro { 52564562Sgshapiro smi_log(SMI_LOG_ERR, 52690792Sgshapiro "%s: listen call failed: %s", name, 52790792Sgshapiro sm_errstring(errno)); 52890792Sgshapiro (void) closesocket(sock); 52966494Sgshapiro return INVALID_SOCKET; 53064562Sgshapiro } 53190792Sgshapiro 53290792Sgshapiro#if NETUNIX 53390792Sgshapiro if (addr.sa.sa_family == AF_UNIX && len > 0) 53490792Sgshapiro { 53590792Sgshapiro /* 53690792Sgshapiro ** Set global variable sockpath so the UNIX socket can be 53790792Sgshapiro ** unlink()ed at exit. 53890792Sgshapiro */ 53990792Sgshapiro 54090792Sgshapiro sockpath = (char *) malloc(len); 54190792Sgshapiro if (sockpath != NULL) 54290792Sgshapiro (void) sm_strlcpy(sockpath, colon, len); 54390792Sgshapiro else 54490792Sgshapiro { 54590792Sgshapiro smi_log(SMI_LOG_ERR, 54690792Sgshapiro "%s: can't malloc(%d) for sockpath: %s", 547110560Sgshapiro name, (int) len, sm_errstring(errno)); 54890792Sgshapiro (void) closesocket(sock); 54990792Sgshapiro return INVALID_SOCKET; 55090792Sgshapiro } 55190792Sgshapiro } 55290792Sgshapiro#endif /* NETUNIX */ 55398121Sgshapiro L_family = addr.sa.sa_family; 55464562Sgshapiro return sock; 55564562Sgshapiro} 556168515Sgshapiro 557168515Sgshapiro#if !_FFR_WORKERS_POOL 55890792Sgshapiro/* 55964562Sgshapiro** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 56064562Sgshapiro** 56164562Sgshapiro** Parameters: 56264562Sgshapiro** arg -- argument to pass to mi_handle_session() 56364562Sgshapiro** 56464562Sgshapiro** Returns: 56564562Sgshapiro** results from mi_handle_session() 56664562Sgshapiro*/ 56764562Sgshapiro 568141858Sgshapirostatic void * 56964562Sgshapiromi_thread_handle_wrapper(arg) 57064562Sgshapiro void *arg; 57164562Sgshapiro{ 572168515Sgshapiro /* 573168515Sgshapiro ** Note: on some systems this generates a compiler warning: 574168515Sgshapiro ** cast to pointer from integer of different size 575168515Sgshapiro ** You can safely ignore this warning as the result of this function 576168515Sgshapiro ** is not used anywhere. 577168515Sgshapiro */ 578168515Sgshapiro 57964562Sgshapiro return (void *) mi_handle_session(arg); 58064562Sgshapiro} 581168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 58264562Sgshapiro 58390792Sgshapiro/* 58466494Sgshapiro** MI_CLOSENER -- close listen socket 58564562Sgshapiro** 58666494Sgshapiro** Parameters: 58766494Sgshapiro** none. 58866494Sgshapiro** 58966494Sgshapiro** Returns: 59066494Sgshapiro** none. 59166494Sgshapiro*/ 59266494Sgshapiro 59366494Sgshapirovoid 59466494Sgshapiromi_closener() 59566494Sgshapiro{ 59671345Sgshapiro (void) smutex_lock(&L_Mutex); 59766494Sgshapiro if (ValidSocket(listenfd)) 59866494Sgshapiro { 59990792Sgshapiro#if NETUNIX 60090792Sgshapiro bool removable; 60190792Sgshapiro struct stat sockinfo; 60290792Sgshapiro struct stat fileinfo; 60390792Sgshapiro 60490792Sgshapiro removable = sockpath != NULL && 60590792Sgshapiro geteuid() != 0 && 60690792Sgshapiro fstat(listenfd, &sockinfo) == 0 && 60790792Sgshapiro (S_ISFIFO(sockinfo.st_mode) 60890792Sgshapiro# ifdef S_ISSOCK 60990792Sgshapiro || S_ISSOCK(sockinfo.st_mode) 610363466Sgshapiro# endif 61190792Sgshapiro ); 61290792Sgshapiro#endif /* NETUNIX */ 61390792Sgshapiro 61490792Sgshapiro (void) closesocket(listenfd); 61566494Sgshapiro listenfd = INVALID_SOCKET; 61690792Sgshapiro 61790792Sgshapiro#if NETUNIX 61890792Sgshapiro /* XXX sleep() some time before doing this? */ 61990792Sgshapiro if (sockpath != NULL) 62090792Sgshapiro { 62190792Sgshapiro if (removable && 62290792Sgshapiro stat(sockpath, &fileinfo) == 0 && 62390792Sgshapiro ((fileinfo.st_dev == sockinfo.st_dev && 62490792Sgshapiro fileinfo.st_ino == sockinfo.st_ino) 62590792Sgshapiro# ifdef S_ISSOCK 62690792Sgshapiro || S_ISSOCK(fileinfo.st_mode) 627363466Sgshapiro# endif 62890792Sgshapiro ) 62990792Sgshapiro && 63090792Sgshapiro (S_ISFIFO(fileinfo.st_mode) 63190792Sgshapiro# ifdef S_ISSOCK 63290792Sgshapiro || S_ISSOCK(fileinfo.st_mode) 633363466Sgshapiro# endif 63490792Sgshapiro )) 63590792Sgshapiro (void) unlink(sockpath); 63690792Sgshapiro free(sockpath); 63790792Sgshapiro sockpath = NULL; 63890792Sgshapiro } 63990792Sgshapiro#endif /* NETUNIX */ 64066494Sgshapiro } 64171345Sgshapiro (void) smutex_unlock(&L_Mutex); 64266494Sgshapiro} 64366494Sgshapiro 64490792Sgshapiro/* 64566494Sgshapiro** MI_LISTENER -- Generic listener harness 64666494Sgshapiro** 64764562Sgshapiro** Open up listen port 64864562Sgshapiro** Wait for connections 64964562Sgshapiro** 65064562Sgshapiro** Parameters: 65164562Sgshapiro** conn -- connection description 65264562Sgshapiro** dbg -- debug level 65364562Sgshapiro** smfi -- filter structure to use 65464562Sgshapiro** timeout -- timeout for reads/writes 655125820Sgshapiro** backlog -- listen queue backlog size 65664562Sgshapiro** 65764562Sgshapiro** Returns: 65864562Sgshapiro** MI_SUCCESS -- Exited normally 65964562Sgshapiro** (session finished or we were told to exit) 66064562Sgshapiro** MI_FAILURE -- Network initialization failed. 66164562Sgshapiro*/ 66264562Sgshapiro 66390792Sgshapiro#if BROKEN_PTHREAD_SLEEP 66473188Sgshapiro 66573188Sgshapiro/* 66673188Sgshapiro** Solaris 2.6, perhaps others, gets an internal threads library panic 66773188Sgshapiro** when sleep() is used: 66873188Sgshapiro** 66973188Sgshapiro** thread_create() failed, returned 11 (EINVAL) 67073188Sgshapiro** co_enable, thr_create() returned error = 24 67173188Sgshapiro** libthread panic: co_enable failed (PID: 17793 LWP 1) 67273188Sgshapiro** stacktrace: 67373188Sgshapiro** ef526b10 67473188Sgshapiro** ef52646c 67573188Sgshapiro** ef534cbc 67673188Sgshapiro** 156a4 67773188Sgshapiro** 14644 67873188Sgshapiro** 1413c 67973188Sgshapiro** 135e0 68073188Sgshapiro** 0 68173188Sgshapiro*/ 68273188Sgshapiro 68390792Sgshapiro# define MI_SLEEP(s) \ 68473188Sgshapiro{ \ 68573188Sgshapiro int rs = 0; \ 68673188Sgshapiro struct timeval st; \ 68773188Sgshapiro \ 68873188Sgshapiro st.tv_sec = (s); \ 68973188Sgshapiro st.tv_usec = 0; \ 69073188Sgshapiro if (st.tv_sec > 0) \ 69173188Sgshapiro { \ 692102528Sgshapiro for (;;) \ 693102528Sgshapiro { \ 694102528Sgshapiro rs = select(0, NULL, NULL, NULL, &st); \ 695102528Sgshapiro if (rs < 0 && errno == EINTR) \ 696102528Sgshapiro continue; \ 697102528Sgshapiro if (rs != 0) \ 698102528Sgshapiro { \ 699102528Sgshapiro smi_log(SMI_LOG_ERR, \ 700110560Sgshapiro "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ 701102528Sgshapiro rs, errno); \ 702102528Sgshapiro } \ 703110560Sgshapiro break; \ 704102528Sgshapiro } \ 70573188Sgshapiro } \ 70673188Sgshapiro} 70790792Sgshapiro#else /* BROKEN_PTHREAD_SLEEP */ 70890792Sgshapiro# define MI_SLEEP(s) sleep((s)) 70990792Sgshapiro#endif /* BROKEN_PTHREAD_SLEEP */ 71073188Sgshapiro 71164562Sgshapiroint 71266494Sgshapiromi_listener(conn, dbg, smfi, timeout, backlog) 71364562Sgshapiro char *conn; 71464562Sgshapiro int dbg; 71564562Sgshapiro smfiDesc_ptr smfi; 71664562Sgshapiro time_t timeout; 71766494Sgshapiro int backlog; 71864562Sgshapiro{ 71966494Sgshapiro socket_t connfd = INVALID_SOCKET; 720132943Sgshapiro#if _FFR_DUP_FD 721132943Sgshapiro socket_t dupfd = INVALID_SOCKET; 722363466Sgshapiro#endif 72364562Sgshapiro int sockopt = 1; 724120256Sgshapiro int r, mistop; 72564562Sgshapiro int ret = MI_SUCCESS; 72690792Sgshapiro int mcnt = 0; /* error count for malloc() failures */ 72790792Sgshapiro int tcnt = 0; /* error count for thread_create() failures */ 72890792Sgshapiro int acnt = 0; /* error count for accept() failures */ 72990792Sgshapiro int scnt = 0; /* error count for select() failures */ 73077349Sgshapiro int save_errno = 0; 731285229Sgshapiro int fdflags; 732168515Sgshapiro#if !_FFR_WORKERS_POOL 73364562Sgshapiro sthread_t thread_id; 734363466Sgshapiro#endif 73564562Sgshapiro _SOCK_ADDR cliaddr; 73664562Sgshapiro SOCKADDR_LEN_T clilen; 73764562Sgshapiro SMFICTX_PTR ctx; 738111823Sgshapiro FD_RD_VAR(rds, excs); 73964562Sgshapiro struct timeval chktime; 74064562Sgshapiro 741125820Sgshapiro if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE) 74264562Sgshapiro return MI_FAILURE; 74371345Sgshapiro 744168515Sgshapiro#if _FFR_WORKERS_POOL 745168515Sgshapiro if (mi_pool_controller_init() == MI_FAILURE) 746168515Sgshapiro return MI_FAILURE; 747363466Sgshapiro#endif 748168515Sgshapiro 74998121Sgshapiro clilen = L_socksize; 750120256Sgshapiro while ((mistop = mi_stop()) == MILTER_CONT) 75164562Sgshapiro { 75271345Sgshapiro (void) smutex_lock(&L_Mutex); 75371345Sgshapiro if (!ValidSocket(listenfd)) 75471345Sgshapiro { 755120256Sgshapiro ret = MI_FAILURE; 756120256Sgshapiro smi_log(SMI_LOG_ERR, 757120256Sgshapiro "%s: listenfd=%d corrupted, terminating, errno=%d", 758120256Sgshapiro smfi->xxfi_name, listenfd, errno); 75971345Sgshapiro (void) smutex_unlock(&L_Mutex); 76071345Sgshapiro break; 76171345Sgshapiro } 76271345Sgshapiro 76364562Sgshapiro /* select on interface ports */ 764111823Sgshapiro FD_RD_INIT(listenfd, rds, excs); 76564562Sgshapiro chktime.tv_sec = MI_CHK_TIME; 76664562Sgshapiro chktime.tv_usec = 0; 767111823Sgshapiro r = FD_RD_READY(listenfd, rds, excs, &chktime); 76864562Sgshapiro if (r == 0) /* timeout */ 76971345Sgshapiro { 77071345Sgshapiro (void) smutex_unlock(&L_Mutex); 77164562Sgshapiro continue; /* just check mi_stop() */ 77271345Sgshapiro } 77364562Sgshapiro if (r < 0) 77464562Sgshapiro { 77577349Sgshapiro save_errno = errno; 77671345Sgshapiro (void) smutex_unlock(&L_Mutex); 77777349Sgshapiro if (save_errno == EINTR) 77864562Sgshapiro continue; 77990792Sgshapiro scnt++; 78090792Sgshapiro smi_log(SMI_LOG_ERR, 781203004Sgshapiro "%s: %s() failed (%s), %s", 782203004Sgshapiro smfi->xxfi_name, MI_POLLSELECT, 783203004Sgshapiro sm_errstring(save_errno), 78490792Sgshapiro scnt >= MAX_FAILS_S ? "abort" : "try again"); 78590792Sgshapiro MI_SLEEP(scnt); 78690792Sgshapiro if (scnt >= MAX_FAILS_S) 78790792Sgshapiro { 78890792Sgshapiro ret = MI_FAILURE; 78990792Sgshapiro break; 79090792Sgshapiro } 79190792Sgshapiro continue; 79264562Sgshapiro } 793111823Sgshapiro if (!FD_IS_RD_RDY(listenfd, rds, excs)) 79464562Sgshapiro { 79564562Sgshapiro /* some error: just stop for now... */ 79664562Sgshapiro ret = MI_FAILURE; 79771345Sgshapiro (void) smutex_unlock(&L_Mutex); 79890792Sgshapiro smi_log(SMI_LOG_ERR, 799111823Sgshapiro "%s: %s() returned exception for socket, abort", 800111823Sgshapiro smfi->xxfi_name, MI_POLLSELECT); 80164562Sgshapiro break; 80264562Sgshapiro } 80390792Sgshapiro scnt = 0; /* reset error counter for select() */ 80464562Sgshapiro 805120256Sgshapiro (void) memset(&cliaddr, '\0', sizeof cliaddr); 80664562Sgshapiro connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 80764562Sgshapiro &clilen); 80877349Sgshapiro save_errno = errno; 80971345Sgshapiro (void) smutex_unlock(&L_Mutex); 81064562Sgshapiro 81173188Sgshapiro /* 812168515Sgshapiro ** If remote side closes before accept() finishes, 813168515Sgshapiro ** sockaddr might not be fully filled in. 81473188Sgshapiro */ 81573188Sgshapiro 81673188Sgshapiro if (ValidSocket(connfd) && 81773188Sgshapiro (clilen == 0 || 81873188Sgshapiro# ifdef BSD4_4_SOCKADDR 81973188Sgshapiro cliaddr.sa.sa_len == 0 || 820363466Sgshapiro# endif 82198121Sgshapiro cliaddr.sa.sa_family != L_family)) 82273188Sgshapiro { 82390792Sgshapiro (void) closesocket(connfd); 82473188Sgshapiro connfd = INVALID_SOCKET; 82577349Sgshapiro save_errno = EINVAL; 82673188Sgshapiro } 82773188Sgshapiro 828110560Sgshapiro /* check if acceptable for select() */ 829110560Sgshapiro if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd)) 830110560Sgshapiro { 831110560Sgshapiro (void) closesocket(connfd); 832110560Sgshapiro connfd = INVALID_SOCKET; 833110560Sgshapiro save_errno = ERANGE; 834110560Sgshapiro } 835110560Sgshapiro 83666494Sgshapiro if (!ValidSocket(connfd)) 83764562Sgshapiro { 838132943Sgshapiro if (save_errno == EINTR 839132943Sgshapiro#ifdef EAGAIN 840132943Sgshapiro || save_errno == EAGAIN 841363466Sgshapiro#endif 842132943Sgshapiro#ifdef ECONNABORTED 843132943Sgshapiro || save_errno == ECONNABORTED 844363466Sgshapiro#endif 845132943Sgshapiro#ifdef EMFILE 846132943Sgshapiro || save_errno == EMFILE 847363466Sgshapiro#endif 848132943Sgshapiro#ifdef ENFILE 849132943Sgshapiro || save_errno == ENFILE 850363466Sgshapiro#endif 851132943Sgshapiro#ifdef ENOBUFS 852132943Sgshapiro || save_errno == ENOBUFS 853363466Sgshapiro#endif 854132943Sgshapiro#ifdef ENOMEM 855132943Sgshapiro || save_errno == ENOMEM 856363466Sgshapiro#endif 857132943Sgshapiro#ifdef ENOSR 858132943Sgshapiro || save_errno == ENOSR 859363466Sgshapiro#endif 860132943Sgshapiro#ifdef EWOULDBLOCK 861132943Sgshapiro || save_errno == EWOULDBLOCK 862363466Sgshapiro#endif 863132943Sgshapiro ) 86477349Sgshapiro continue; 86577349Sgshapiro acnt++; 86690792Sgshapiro smi_log(SMI_LOG_ERR, 86790792Sgshapiro "%s: accept() returned invalid socket (%s), %s", 86890792Sgshapiro smfi->xxfi_name, sm_errstring(save_errno), 86990792Sgshapiro acnt >= MAX_FAILS_A ? "abort" : "try again"); 87077349Sgshapiro MI_SLEEP(acnt); 87177349Sgshapiro if (acnt >= MAX_FAILS_A) 87277349Sgshapiro { 87377349Sgshapiro ret = MI_FAILURE; 87477349Sgshapiro break; 87577349Sgshapiro } 87664562Sgshapiro continue; 87764562Sgshapiro } 87890792Sgshapiro acnt = 0; /* reset error counter for accept() */ 879132943Sgshapiro#if _FFR_DUP_FD 880132943Sgshapiro dupfd = fcntl(connfd, F_DUPFD, 256); 881168515Sgshapiro if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd)) 882132943Sgshapiro { 883132943Sgshapiro close(connfd); 884132943Sgshapiro connfd = dupfd; 885132943Sgshapiro dupfd = INVALID_SOCKET; 886132943Sgshapiro } 887132943Sgshapiro#endif /* _FFR_DUP_FD */ 88864562Sgshapiro 889363466Sgshapiro /* 890285229Sgshapiro ** Need to set close-on-exec for connfd in case a user's 891285229Sgshapiro ** filter starts other applications. 892285229Sgshapiro ** Note: errors will not stop processing (for now). 893285229Sgshapiro */ 894285229Sgshapiro 895285229Sgshapiro if ((fdflags = fcntl(connfd, F_GETFD, 0)) == -1 || 896285229Sgshapiro fcntl(connfd, F_SETFD, fdflags | FD_CLOEXEC) == -1) 897285229Sgshapiro { 898285229Sgshapiro smi_log(SMI_LOG_ERR, 899285229Sgshapiro "%s: Unable to set close-on-exec: %s", 900285229Sgshapiro smfi->xxfi_name, sm_errstring(errno)); 901285229Sgshapiro } 902285229Sgshapiro 90364562Sgshapiro if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 90464562Sgshapiro (void *) &sockopt, sizeof sockopt) < 0) 90564562Sgshapiro { 906157001Sgshapiro smi_log(SMI_LOG_WARN, 907157001Sgshapiro "%s: set keepalive failed (%s)", 90890792Sgshapiro smfi->xxfi_name, sm_errstring(errno)); 90964562Sgshapiro /* XXX: continue? */ 91064562Sgshapiro } 91164562Sgshapiro if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 91264562Sgshapiro { 91390792Sgshapiro (void) closesocket(connfd); 91473188Sgshapiro mcnt++; 91590792Sgshapiro smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s", 91690792Sgshapiro smfi->xxfi_name, sm_errstring(save_errno), 91790792Sgshapiro mcnt >= MAX_FAILS_M ? "abort" : "try again"); 91873188Sgshapiro MI_SLEEP(mcnt); 91973188Sgshapiro if (mcnt >= MAX_FAILS_M) 92064562Sgshapiro { 92164562Sgshapiro ret = MI_FAILURE; 92264562Sgshapiro break; 92364562Sgshapiro } 92464562Sgshapiro continue; 92564562Sgshapiro } 92690792Sgshapiro mcnt = 0; /* reset error counter for malloc() */ 927120256Sgshapiro (void) memset(ctx, '\0', sizeof *ctx); 92864562Sgshapiro ctx->ctx_sd = connfd; 92964562Sgshapiro ctx->ctx_dbg = dbg; 93064562Sgshapiro ctx->ctx_timeout = timeout; 93164562Sgshapiro ctx->ctx_smfi = smfi; 93264562Sgshapiro if (smfi->xxfi_connect == NULL) 93364562Sgshapiro ctx->ctx_pflags |= SMFIP_NOCONNECT; 93464562Sgshapiro if (smfi->xxfi_helo == NULL) 93564562Sgshapiro ctx->ctx_pflags |= SMFIP_NOHELO; 93664562Sgshapiro if (smfi->xxfi_envfrom == NULL) 93764562Sgshapiro ctx->ctx_pflags |= SMFIP_NOMAIL; 93864562Sgshapiro if (smfi->xxfi_envrcpt == NULL) 93964562Sgshapiro ctx->ctx_pflags |= SMFIP_NORCPT; 94064562Sgshapiro if (smfi->xxfi_header == NULL) 94164562Sgshapiro ctx->ctx_pflags |= SMFIP_NOHDRS; 94264562Sgshapiro if (smfi->xxfi_eoh == NULL) 94364562Sgshapiro ctx->ctx_pflags |= SMFIP_NOEOH; 94464562Sgshapiro if (smfi->xxfi_body == NULL) 94564562Sgshapiro ctx->ctx_pflags |= SMFIP_NOBODY; 946168988Sgshapiro if (smfi->xxfi_version <= 3 || smfi->xxfi_data == NULL) 947168515Sgshapiro ctx->ctx_pflags |= SMFIP_NODATA; 948168988Sgshapiro if (smfi->xxfi_version <= 2 || smfi->xxfi_unknown == NULL) 949168515Sgshapiro ctx->ctx_pflags |= SMFIP_NOUNKNOWN; 95064562Sgshapiro 951168515Sgshapiro#if _FFR_WORKERS_POOL 952168515Sgshapiro# define LOG_CRT_FAIL "%s: mi_start_session() failed: %d, %s" 953168515Sgshapiro if ((r = mi_start_session(ctx)) != MI_SUCCESS) 954363466Sgshapiro#else 955168515Sgshapiro# define LOG_CRT_FAIL "%s: thread_create() failed: %d, %s" 95664562Sgshapiro if ((r = thread_create(&thread_id, 95764562Sgshapiro mi_thread_handle_wrapper, 95871345Sgshapiro (void *) ctx)) != 0) 959363466Sgshapiro#endif 96064562Sgshapiro { 96190792Sgshapiro tcnt++; 96264562Sgshapiro smi_log(SMI_LOG_ERR, 963168515Sgshapiro LOG_CRT_FAIL, 96490792Sgshapiro smfi->xxfi_name, r, 96590792Sgshapiro tcnt >= MAX_FAILS_T ? "abort" : "try again"); 96673188Sgshapiro MI_SLEEP(tcnt); 96790792Sgshapiro (void) closesocket(connfd); 96864562Sgshapiro free(ctx); 96973188Sgshapiro if (tcnt >= MAX_FAILS_T) 97064562Sgshapiro { 97164562Sgshapiro ret = MI_FAILURE; 97264562Sgshapiro break; 97364562Sgshapiro } 97464562Sgshapiro continue; 97564562Sgshapiro } 97673188Sgshapiro tcnt = 0; 97764562Sgshapiro } 97864562Sgshapiro if (ret != MI_SUCCESS) 97964562Sgshapiro mi_stop_milters(MILTER_ABRT); 98071345Sgshapiro else 981120256Sgshapiro { 982120256Sgshapiro if (mistop != MILTER_CONT) 983120256Sgshapiro smi_log(SMI_LOG_INFO, "%s: mi_stop=%d", 984120256Sgshapiro smfi->xxfi_name, mistop); 98571345Sgshapiro mi_closener(); 986120256Sgshapiro } 98771345Sgshapiro (void) smutex_destroy(&L_Mutex); 98864562Sgshapiro return ret; 98964562Sgshapiro} 990