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