17c478bd9Sstevel@tonic-gate /* 2445f2479Sjbeck * Copyright (c) 1999-2006 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 77c478bd9Sstevel@tonic-gate * the sendmail distribution. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 127c478bd9Sstevel@tonic-gate 137c478bd9Sstevel@tonic-gate #include <sm/gen.h> 14*058561cbSjbeck SM_RCSID("@(#)$Id: listener.c,v 8.122 2006/11/02 17:54:44 ca Exp $") 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate /* 177c478bd9Sstevel@tonic-gate ** listener.c -- threaded network listener 187c478bd9Sstevel@tonic-gate */ 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate #include "libmilter.h" 217c478bd9Sstevel@tonic-gate #include <sm/errstring.h> 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate #include <sys/types.h> 247c478bd9Sstevel@tonic-gate #include <sys/stat.h> 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate # if NETINET || NETINET6 287c478bd9Sstevel@tonic-gate # include <arpa/inet.h> 297c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 30*058561cbSjbeck # if SM_CONF_POLL 31*058561cbSjbeck # undef SM_FD_OK_SELECT 32*058561cbSjbeck # define SM_FD_OK_SELECT(fd) true 33*058561cbSjbeck # endif /* SM_CONF_POLL */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate static smutex_t L_Mutex; 367c478bd9Sstevel@tonic-gate static int L_family; 377c478bd9Sstevel@tonic-gate static SOCKADDR_LEN_T L_socksize; 387c478bd9Sstevel@tonic-gate static socket_t listenfd = INVALID_SOCKET; 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate static socket_t mi_milteropen __P((char *, int, bool, char *)); 41*058561cbSjbeck #if !_FFR_WORKERS_POOL 427c478bd9Sstevel@tonic-gate static void *mi_thread_handle_wrapper __P((void *)); 43*058561cbSjbeck #endif /* !_FFR_WORKERS_POOL */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate ** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet 477c478bd9Sstevel@tonic-gate ** 487c478bd9Sstevel@tonic-gate ** Parameters: 497c478bd9Sstevel@tonic-gate ** conn -- connection description 507c478bd9Sstevel@tonic-gate ** backlog -- listen backlog 517c478bd9Sstevel@tonic-gate ** dbg -- debug level 527c478bd9Sstevel@tonic-gate ** rmsocket -- if true, try to unlink() the socket first 537c478bd9Sstevel@tonic-gate ** (UNIX domain sockets only) 547c478bd9Sstevel@tonic-gate ** smfi -- filter structure to use 557c478bd9Sstevel@tonic-gate ** 567c478bd9Sstevel@tonic-gate ** Return value: 577c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate int 617c478bd9Sstevel@tonic-gate mi_opensocket(conn, backlog, dbg, rmsocket, smfi) 627c478bd9Sstevel@tonic-gate char *conn; 637c478bd9Sstevel@tonic-gate int backlog; 647c478bd9Sstevel@tonic-gate int dbg; 657c478bd9Sstevel@tonic-gate bool rmsocket; 667c478bd9Sstevel@tonic-gate smfiDesc_ptr smfi; 677c478bd9Sstevel@tonic-gate { 687c478bd9Sstevel@tonic-gate if (smfi == NULL || conn == NULL) 697c478bd9Sstevel@tonic-gate return MI_FAILURE; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate if (ValidSocket(listenfd)) 727c478bd9Sstevel@tonic-gate return MI_SUCCESS; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate if (dbg > 0) 757c478bd9Sstevel@tonic-gate { 767c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_DEBUG, 777c478bd9Sstevel@tonic-gate "%s: Opening listen socket on conn %s", 787c478bd9Sstevel@tonic-gate smfi->xxfi_name, conn); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate (void) smutex_init(&L_Mutex); 817c478bd9Sstevel@tonic-gate (void) smutex_lock(&L_Mutex); 827c478bd9Sstevel@tonic-gate listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name); 837c478bd9Sstevel@tonic-gate if (!ValidSocket(listenfd)) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_FATAL, 867c478bd9Sstevel@tonic-gate "%s: Unable to create listening socket on conn %s", 877c478bd9Sstevel@tonic-gate smfi->xxfi_name, conn); 887c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 897c478bd9Sstevel@tonic-gate return MI_FAILURE; 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate if (!SM_FD_OK_SELECT(listenfd)) 927c478bd9Sstevel@tonic-gate { 937c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 947c478bd9Sstevel@tonic-gate smfi->xxfi_name, listenfd, FD_SETSIZE); 957c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 967c478bd9Sstevel@tonic-gate return MI_FAILURE; 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 997c478bd9Sstevel@tonic-gate return MI_SUCCESS; 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate ** MI_MILTEROPEN -- setup socket to listen on 1047c478bd9Sstevel@tonic-gate ** 1057c478bd9Sstevel@tonic-gate ** Parameters: 1067c478bd9Sstevel@tonic-gate ** conn -- connection description 1077c478bd9Sstevel@tonic-gate ** backlog -- listen backlog 1087c478bd9Sstevel@tonic-gate ** rmsocket -- if true, try to unlink() the socket first 1097c478bd9Sstevel@tonic-gate ** (UNIX domain sockets only) 1107c478bd9Sstevel@tonic-gate ** name -- name for logging 1117c478bd9Sstevel@tonic-gate ** 1127c478bd9Sstevel@tonic-gate ** Returns: 1137c478bd9Sstevel@tonic-gate ** socket upon success, error code otherwise. 1147c478bd9Sstevel@tonic-gate ** 1157c478bd9Sstevel@tonic-gate ** Side effect: 1167c478bd9Sstevel@tonic-gate ** sets sockpath if UNIX socket. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate #if NETUNIX 1207c478bd9Sstevel@tonic-gate static char *sockpath = NULL; 1217c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static socket_t 1247c478bd9Sstevel@tonic-gate mi_milteropen(conn, backlog, rmsocket, name) 1257c478bd9Sstevel@tonic-gate char *conn; 1267c478bd9Sstevel@tonic-gate int backlog; 1277c478bd9Sstevel@tonic-gate bool rmsocket; 1287c478bd9Sstevel@tonic-gate char *name; 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate socket_t sock; 1317c478bd9Sstevel@tonic-gate int sockopt = 1; 1327c478bd9Sstevel@tonic-gate int fdflags; 1337c478bd9Sstevel@tonic-gate size_t len = 0; 1347c478bd9Sstevel@tonic-gate char *p; 1357c478bd9Sstevel@tonic-gate char *colon; 1367c478bd9Sstevel@tonic-gate char *at; 1377c478bd9Sstevel@tonic-gate SOCKADDR addr; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate if (conn == NULL || conn[0] == '\0') 1407c478bd9Sstevel@tonic-gate { 1417c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", 1427c478bd9Sstevel@tonic-gate name); 1437c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate (void) memset(&addr, '\0', sizeof addr); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* protocol:filename or protocol:port@host */ 1487c478bd9Sstevel@tonic-gate p = conn; 1497c478bd9Sstevel@tonic-gate colon = strchr(p, ':'); 1507c478bd9Sstevel@tonic-gate if (colon != NULL) 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate *colon = '\0'; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (*p == '\0') 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate #if NETUNIX 1577c478bd9Sstevel@tonic-gate /* default to AF_UNIX */ 1587c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 1597c478bd9Sstevel@tonic-gate L_socksize = sizeof (struct sockaddr_un); 1607c478bd9Sstevel@tonic-gate #else /* NETUNIX */ 1617c478bd9Sstevel@tonic-gate # if NETINET 1627c478bd9Sstevel@tonic-gate /* default to AF_INET */ 1637c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 1647c478bd9Sstevel@tonic-gate L_socksize = sizeof addr.sin; 1657c478bd9Sstevel@tonic-gate # else /* NETINET */ 1667c478bd9Sstevel@tonic-gate # if NETINET6 1677c478bd9Sstevel@tonic-gate /* default to AF_INET6 */ 1687c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 1697c478bd9Sstevel@tonic-gate L_socksize = sizeof addr.sin6; 1707c478bd9Sstevel@tonic-gate # else /* NETINET6 */ 1717c478bd9Sstevel@tonic-gate /* no protocols available */ 1727c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1737c478bd9Sstevel@tonic-gate "%s: no valid socket protocols available", 1747c478bd9Sstevel@tonic-gate name); 1757c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 1767c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1777c478bd9Sstevel@tonic-gate # endif /* NETINET */ 1787c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate #if NETUNIX 1817c478bd9Sstevel@tonic-gate else if (strcasecmp(p, "unix") == 0 || 1827c478bd9Sstevel@tonic-gate strcasecmp(p, "local") == 0) 1837c478bd9Sstevel@tonic-gate { 1847c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 1857c478bd9Sstevel@tonic-gate L_socksize = sizeof (struct sockaddr_un); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 1887c478bd9Sstevel@tonic-gate #if NETINET 1897c478bd9Sstevel@tonic-gate else if (strcasecmp(p, "inet") == 0) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 1927c478bd9Sstevel@tonic-gate L_socksize = sizeof addr.sin; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate #endif /* NETINET */ 1957c478bd9Sstevel@tonic-gate #if NETINET6 1967c478bd9Sstevel@tonic-gate else if (strcasecmp(p, "inet6") == 0) 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 1997c478bd9Sstevel@tonic-gate L_socksize = sizeof addr.sin6; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate #endif /* NETINET6 */ 2027c478bd9Sstevel@tonic-gate else 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 2057c478bd9Sstevel@tonic-gate name, p); 2067c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate *colon++ = ':'; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate else 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate colon = p; 2137c478bd9Sstevel@tonic-gate #if NETUNIX 2147c478bd9Sstevel@tonic-gate /* default to AF_UNIX */ 2157c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 2167c478bd9Sstevel@tonic-gate L_socksize = sizeof (struct sockaddr_un); 2177c478bd9Sstevel@tonic-gate #else /* NETUNIX */ 2187c478bd9Sstevel@tonic-gate # if NETINET 2197c478bd9Sstevel@tonic-gate /* default to AF_INET */ 2207c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 2217c478bd9Sstevel@tonic-gate L_socksize = sizeof addr.sin; 2227c478bd9Sstevel@tonic-gate # else /* NETINET */ 2237c478bd9Sstevel@tonic-gate # if NETINET6 2247c478bd9Sstevel@tonic-gate /* default to AF_INET6 */ 2257c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 2267c478bd9Sstevel@tonic-gate L_socksize = sizeof addr.sin6; 2277c478bd9Sstevel@tonic-gate # else /* NETINET6 */ 2287c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 2297c478bd9Sstevel@tonic-gate name, p); 2307c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 2317c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 2327c478bd9Sstevel@tonic-gate # endif /* NETINET */ 2337c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate #if NETUNIX 2377c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_UNIX) 2387c478bd9Sstevel@tonic-gate { 2397c478bd9Sstevel@tonic-gate # if 0 2407c478bd9Sstevel@tonic-gate long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 2417c478bd9Sstevel@tonic-gate # endif /* 0 */ 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate at = colon; 2447c478bd9Sstevel@tonic-gate len = strlen(colon) + 1; 2457c478bd9Sstevel@tonic-gate if (len >= sizeof addr.sunix.sun_path) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate errno = EINVAL; 2487c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", 2497c478bd9Sstevel@tonic-gate name, colon); 2507c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate (void) sm_strlcpy(addr.sunix.sun_path, colon, 2537c478bd9Sstevel@tonic-gate sizeof addr.sunix.sun_path); 2547c478bd9Sstevel@tonic-gate # if 0 2557c478bd9Sstevel@tonic-gate errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 2567c478bd9Sstevel@tonic-gate S_IRUSR|S_IWUSR, NULL); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* if not safe, don't create */ 2597c478bd9Sstevel@tonic-gate if (errno != 0) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 2627c478bd9Sstevel@tonic-gate "%s: UNIX socket name %s unsafe", 2637c478bd9Sstevel@tonic-gate name, colon); 2647c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate # endif /* 0 */ 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate #if NETINET || NETINET6 2717c478bd9Sstevel@tonic-gate if ( 2727c478bd9Sstevel@tonic-gate # if NETINET 2737c478bd9Sstevel@tonic-gate addr.sa.sa_family == AF_INET 2747c478bd9Sstevel@tonic-gate # endif /* NETINET */ 2757c478bd9Sstevel@tonic-gate # if NETINET && NETINET6 2767c478bd9Sstevel@tonic-gate || 2777c478bd9Sstevel@tonic-gate # endif /* NETINET && NETINET6 */ 2787c478bd9Sstevel@tonic-gate # if NETINET6 2797c478bd9Sstevel@tonic-gate addr.sa.sa_family == AF_INET6 2807c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 2817c478bd9Sstevel@tonic-gate ) 2827c478bd9Sstevel@tonic-gate { 2837c478bd9Sstevel@tonic-gate unsigned short port; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate /* Parse port@host */ 2867c478bd9Sstevel@tonic-gate at = strchr(colon, '@'); 2877c478bd9Sstevel@tonic-gate if (at == NULL) 2887c478bd9Sstevel@tonic-gate { 2897c478bd9Sstevel@tonic-gate switch (addr.sa.sa_family) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate # if NETINET 2927c478bd9Sstevel@tonic-gate case AF_INET: 2937c478bd9Sstevel@tonic-gate addr.sin.sin_addr.s_addr = INADDR_ANY; 2947c478bd9Sstevel@tonic-gate break; 2957c478bd9Sstevel@tonic-gate # endif /* NETINET */ 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate # if NETINET6 2987c478bd9Sstevel@tonic-gate case AF_INET6: 2997c478bd9Sstevel@tonic-gate addr.sin6.sin6_addr = in6addr_any; 3007c478bd9Sstevel@tonic-gate break; 3017c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate else 3057c478bd9Sstevel@tonic-gate *at = '\0'; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if (isascii(*colon) && isdigit(*colon)) 3087c478bd9Sstevel@tonic-gate port = htons((unsigned short) atoi(colon)); 3097c478bd9Sstevel@tonic-gate else 3107c478bd9Sstevel@tonic-gate { 3117c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME 3127c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: invalid port number %s", 3137c478bd9Sstevel@tonic-gate name, colon); 3147c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 3157c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */ 3167c478bd9Sstevel@tonic-gate register struct servent *sp; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate sp = getservbyname(colon, "tcp"); 3197c478bd9Sstevel@tonic-gate if (sp == NULL) 3207c478bd9Sstevel@tonic-gate { 3217c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 3227c478bd9Sstevel@tonic-gate "%s: unknown port name %s", 3237c478bd9Sstevel@tonic-gate name, colon); 3247c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate port = sp->s_port; 3277c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */ 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate if (at != NULL) 3307c478bd9Sstevel@tonic-gate { 3317c478bd9Sstevel@tonic-gate *at++ = '@'; 3327c478bd9Sstevel@tonic-gate if (*at == '[') 3337c478bd9Sstevel@tonic-gate { 3347c478bd9Sstevel@tonic-gate char *end; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate end = strchr(at, ']'); 3377c478bd9Sstevel@tonic-gate if (end != NULL) 3387c478bd9Sstevel@tonic-gate { 3397c478bd9Sstevel@tonic-gate bool found = false; 3407c478bd9Sstevel@tonic-gate # if NETINET 3417c478bd9Sstevel@tonic-gate unsigned long hid = INADDR_NONE; 3427c478bd9Sstevel@tonic-gate # endif /* NETINET */ 3437c478bd9Sstevel@tonic-gate # if NETINET6 3447c478bd9Sstevel@tonic-gate struct sockaddr_in6 hid6; 3457c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate *end = '\0'; 3487c478bd9Sstevel@tonic-gate # if NETINET 3497c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET && 3507c478bd9Sstevel@tonic-gate (hid = inet_addr(&at[1])) != INADDR_NONE) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate addr.sin.sin_addr.s_addr = hid; 3537c478bd9Sstevel@tonic-gate addr.sin.sin_port = port; 3547c478bd9Sstevel@tonic-gate found = true; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate # endif /* NETINET */ 3577c478bd9Sstevel@tonic-gate # if NETINET6 3587c478bd9Sstevel@tonic-gate (void) memset(&hid6, '\0', sizeof hid6); 3597c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET6 && 3607c478bd9Sstevel@tonic-gate mi_inet_pton(AF_INET6, &at[1], 3617c478bd9Sstevel@tonic-gate &hid6.sin6_addr) == 1) 3627c478bd9Sstevel@tonic-gate { 3637c478bd9Sstevel@tonic-gate addr.sin6.sin6_addr = hid6.sin6_addr; 3647c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port; 3657c478bd9Sstevel@tonic-gate found = true; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 3687c478bd9Sstevel@tonic-gate *end = ']'; 3697c478bd9Sstevel@tonic-gate if (!found) 3707c478bd9Sstevel@tonic-gate { 3717c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 3727c478bd9Sstevel@tonic-gate "%s: Invalid numeric domain spec \"%s\"", 3737c478bd9Sstevel@tonic-gate name, at); 3747c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate else 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 3807c478bd9Sstevel@tonic-gate "%s: Invalid numeric domain spec \"%s\"", 3817c478bd9Sstevel@tonic-gate name, at); 3827c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate else 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate hp = mi_gethostbyname(at, addr.sa.sa_family); 3907c478bd9Sstevel@tonic-gate if (hp == NULL) 3917c478bd9Sstevel@tonic-gate { 3927c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 3937c478bd9Sstevel@tonic-gate "%s: Unknown host name %s", 3947c478bd9Sstevel@tonic-gate name, at); 3957c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate addr.sa.sa_family = hp->h_addrtype; 3987c478bd9Sstevel@tonic-gate switch (hp->h_addrtype) 3997c478bd9Sstevel@tonic-gate { 4007c478bd9Sstevel@tonic-gate # if NETINET 4017c478bd9Sstevel@tonic-gate case AF_INET: 4027c478bd9Sstevel@tonic-gate (void) memmove(&addr.sin.sin_addr, 4037c478bd9Sstevel@tonic-gate hp->h_addr, 4047c478bd9Sstevel@tonic-gate INADDRSZ); 4057c478bd9Sstevel@tonic-gate addr.sin.sin_port = port; 4067c478bd9Sstevel@tonic-gate break; 4077c478bd9Sstevel@tonic-gate # endif /* NETINET */ 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate # if NETINET6 4107c478bd9Sstevel@tonic-gate case AF_INET6: 4117c478bd9Sstevel@tonic-gate (void) memmove(&addr.sin6.sin6_addr, 4127c478bd9Sstevel@tonic-gate hp->h_addr, 4137c478bd9Sstevel@tonic-gate IN6ADDRSZ); 4147c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port; 4157c478bd9Sstevel@tonic-gate break; 4167c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate default: 4197c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 4207c478bd9Sstevel@tonic-gate "%s: Unknown protocol for %s (%d)", 4217c478bd9Sstevel@tonic-gate name, at, hp->h_addrtype); 4227c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate # if NETINET6 4257c478bd9Sstevel@tonic-gate freehostent(hp); 4267c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate else 4307c478bd9Sstevel@tonic-gate { 4317c478bd9Sstevel@tonic-gate switch (addr.sa.sa_family) 4327c478bd9Sstevel@tonic-gate { 4337c478bd9Sstevel@tonic-gate # if NETINET 4347c478bd9Sstevel@tonic-gate case AF_INET: 4357c478bd9Sstevel@tonic-gate addr.sin.sin_port = port; 4367c478bd9Sstevel@tonic-gate break; 4377c478bd9Sstevel@tonic-gate # endif /* NETINET */ 4387c478bd9Sstevel@tonic-gate # if NETINET6 4397c478bd9Sstevel@tonic-gate case AF_INET6: 4407c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port; 4417c478bd9Sstevel@tonic-gate break; 4427c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 4497c478bd9Sstevel@tonic-gate if (!ValidSocket(sock)) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 4527c478bd9Sstevel@tonic-gate "%s: Unable to create new socket: %s", 4537c478bd9Sstevel@tonic-gate name, sm_errstring(errno)); 4547c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 || 4587c478bd9Sstevel@tonic-gate fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1) 4597c478bd9Sstevel@tonic-gate { 4607c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 4617c478bd9Sstevel@tonic-gate "%s: Unable to set close-on-exec: %s", name, 4627c478bd9Sstevel@tonic-gate sm_errstring(errno)); 4637c478bd9Sstevel@tonic-gate (void) closesocket(sock); 4647c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 467445f2479Sjbeck if ( 468445f2479Sjbeck #if NETUNIX 469445f2479Sjbeck addr.sa.sa_family != AF_UNIX && 470445f2479Sjbeck #endif /* NETUNIX */ 471445f2479Sjbeck setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 4727c478bd9Sstevel@tonic-gate sizeof(sockopt)) == -1) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 475445f2479Sjbeck "%s: set reuseaddr failed (%s)", name, 4767c478bd9Sstevel@tonic-gate sm_errstring(errno)); 4777c478bd9Sstevel@tonic-gate (void) closesocket(sock); 4787c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate #if NETUNIX 4827c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_UNIX && rmsocket) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate struct stat s; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (stat(colon, &s) != 0) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate if (errno != ENOENT) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 4917c478bd9Sstevel@tonic-gate "%s: Unable to stat() %s: %s", 4927c478bd9Sstevel@tonic-gate name, colon, sm_errstring(errno)); 4937c478bd9Sstevel@tonic-gate (void) closesocket(sock); 4947c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate else if (!S_ISSOCK(s.st_mode)) 4987c478bd9Sstevel@tonic-gate { 4997c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 5007c478bd9Sstevel@tonic-gate "%s: %s is not a UNIX domain socket", 5017c478bd9Sstevel@tonic-gate name, colon); 5027c478bd9Sstevel@tonic-gate (void) closesocket(sock); 5037c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate else if (unlink(colon) != 0) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 5087c478bd9Sstevel@tonic-gate "%s: Unable to remove %s: %s", 5097c478bd9Sstevel@tonic-gate name, colon, sm_errstring(errno)); 5107c478bd9Sstevel@tonic-gate (void) closesocket(sock); 5117c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate if (bind(sock, &addr.sa, L_socksize) < 0) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 5197c478bd9Sstevel@tonic-gate "%s: Unable to bind to port %s: %s", 5207c478bd9Sstevel@tonic-gate name, conn, sm_errstring(errno)); 5217c478bd9Sstevel@tonic-gate (void) closesocket(sock); 5227c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate if (listen(sock, backlog) < 0) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 5287c478bd9Sstevel@tonic-gate "%s: listen call failed: %s", name, 5297c478bd9Sstevel@tonic-gate sm_errstring(errno)); 5307c478bd9Sstevel@tonic-gate (void) closesocket(sock); 5317c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate #if NETUNIX 5357c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_UNIX && len > 0) 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate ** Set global variable sockpath so the UNIX socket can be 5397c478bd9Sstevel@tonic-gate ** unlink()ed at exit. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate sockpath = (char *) malloc(len); 5437c478bd9Sstevel@tonic-gate if (sockpath != NULL) 5447c478bd9Sstevel@tonic-gate (void) sm_strlcpy(sockpath, colon, len); 5457c478bd9Sstevel@tonic-gate else 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 5487c478bd9Sstevel@tonic-gate "%s: can't malloc(%d) for sockpath: %s", 5497c478bd9Sstevel@tonic-gate name, (int) len, sm_errstring(errno)); 5507c478bd9Sstevel@tonic-gate (void) closesocket(sock); 5517c478bd9Sstevel@tonic-gate return INVALID_SOCKET; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 5557c478bd9Sstevel@tonic-gate L_family = addr.sa.sa_family; 5567c478bd9Sstevel@tonic-gate return sock; 5577c478bd9Sstevel@tonic-gate } 558*058561cbSjbeck 559*058561cbSjbeck #if !_FFR_WORKERS_POOL 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate ** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 5627c478bd9Sstevel@tonic-gate ** 5637c478bd9Sstevel@tonic-gate ** Parameters: 5647c478bd9Sstevel@tonic-gate ** arg -- argument to pass to mi_handle_session() 5657c478bd9Sstevel@tonic-gate ** 5667c478bd9Sstevel@tonic-gate ** Returns: 5677c478bd9Sstevel@tonic-gate ** results from mi_handle_session() 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate static void * 5717c478bd9Sstevel@tonic-gate mi_thread_handle_wrapper(arg) 5727c478bd9Sstevel@tonic-gate void *arg; 5737c478bd9Sstevel@tonic-gate { 574*058561cbSjbeck /* 575*058561cbSjbeck ** Note: on some systems this generates a compiler warning: 576*058561cbSjbeck ** cast to pointer from integer of different size 577*058561cbSjbeck ** You can safely ignore this warning as the result of this function 578*058561cbSjbeck ** is not used anywhere. 579*058561cbSjbeck */ 580*058561cbSjbeck 5817c478bd9Sstevel@tonic-gate return (void *) mi_handle_session(arg); 5827c478bd9Sstevel@tonic-gate } 583*058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate ** MI_CLOSENER -- close listen socket 5877c478bd9Sstevel@tonic-gate ** 5887c478bd9Sstevel@tonic-gate ** Parameters: 5897c478bd9Sstevel@tonic-gate ** none. 5907c478bd9Sstevel@tonic-gate ** 5917c478bd9Sstevel@tonic-gate ** Returns: 5927c478bd9Sstevel@tonic-gate ** none. 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate void 5967c478bd9Sstevel@tonic-gate mi_closener() 5977c478bd9Sstevel@tonic-gate { 5987c478bd9Sstevel@tonic-gate (void) smutex_lock(&L_Mutex); 5997c478bd9Sstevel@tonic-gate if (ValidSocket(listenfd)) 6007c478bd9Sstevel@tonic-gate { 6017c478bd9Sstevel@tonic-gate #if NETUNIX 6027c478bd9Sstevel@tonic-gate bool removable; 6037c478bd9Sstevel@tonic-gate struct stat sockinfo; 6047c478bd9Sstevel@tonic-gate struct stat fileinfo; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate removable = sockpath != NULL && 6077c478bd9Sstevel@tonic-gate geteuid() != 0 && 6087c478bd9Sstevel@tonic-gate fstat(listenfd, &sockinfo) == 0 && 6097c478bd9Sstevel@tonic-gate (S_ISFIFO(sockinfo.st_mode) 6107c478bd9Sstevel@tonic-gate # ifdef S_ISSOCK 6117c478bd9Sstevel@tonic-gate || S_ISSOCK(sockinfo.st_mode) 6127c478bd9Sstevel@tonic-gate # endif /* S_ISSOCK */ 6137c478bd9Sstevel@tonic-gate ); 6147c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate (void) closesocket(listenfd); 6177c478bd9Sstevel@tonic-gate listenfd = INVALID_SOCKET; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate #if NETUNIX 6207c478bd9Sstevel@tonic-gate /* XXX sleep() some time before doing this? */ 6217c478bd9Sstevel@tonic-gate if (sockpath != NULL) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate if (removable && 6247c478bd9Sstevel@tonic-gate stat(sockpath, &fileinfo) == 0 && 6257c478bd9Sstevel@tonic-gate ((fileinfo.st_dev == sockinfo.st_dev && 6267c478bd9Sstevel@tonic-gate fileinfo.st_ino == sockinfo.st_ino) 6277c478bd9Sstevel@tonic-gate # ifdef S_ISSOCK 6287c478bd9Sstevel@tonic-gate || S_ISSOCK(fileinfo.st_mode) 6297c478bd9Sstevel@tonic-gate # endif /* S_ISSOCK */ 6307c478bd9Sstevel@tonic-gate ) 6317c478bd9Sstevel@tonic-gate && 6327c478bd9Sstevel@tonic-gate (S_ISFIFO(fileinfo.st_mode) 6337c478bd9Sstevel@tonic-gate # ifdef S_ISSOCK 6347c478bd9Sstevel@tonic-gate || S_ISSOCK(fileinfo.st_mode) 6357c478bd9Sstevel@tonic-gate # endif /* S_ISSOCK */ 6367c478bd9Sstevel@tonic-gate )) 6377c478bd9Sstevel@tonic-gate (void) unlink(sockpath); 6387c478bd9Sstevel@tonic-gate free(sockpath); 6397c478bd9Sstevel@tonic-gate sockpath = NULL; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate #endif /* NETUNIX */ 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate ** MI_LISTENER -- Generic listener harness 6487c478bd9Sstevel@tonic-gate ** 6497c478bd9Sstevel@tonic-gate ** Open up listen port 6507c478bd9Sstevel@tonic-gate ** Wait for connections 6517c478bd9Sstevel@tonic-gate ** 6527c478bd9Sstevel@tonic-gate ** Parameters: 6537c478bd9Sstevel@tonic-gate ** conn -- connection description 6547c478bd9Sstevel@tonic-gate ** dbg -- debug level 6557c478bd9Sstevel@tonic-gate ** smfi -- filter structure to use 6567c478bd9Sstevel@tonic-gate ** timeout -- timeout for reads/writes 6577c478bd9Sstevel@tonic-gate ** backlog -- listen queue backlog size 6587c478bd9Sstevel@tonic-gate ** 6597c478bd9Sstevel@tonic-gate ** Returns: 6607c478bd9Sstevel@tonic-gate ** MI_SUCCESS -- Exited normally 6617c478bd9Sstevel@tonic-gate ** (session finished or we were told to exit) 6627c478bd9Sstevel@tonic-gate ** MI_FAILURE -- Network initialization failed. 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate #if BROKEN_PTHREAD_SLEEP 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate ** Solaris 2.6, perhaps others, gets an internal threads library panic 6697c478bd9Sstevel@tonic-gate ** when sleep() is used: 6707c478bd9Sstevel@tonic-gate ** 6717c478bd9Sstevel@tonic-gate ** thread_create() failed, returned 11 (EINVAL) 6727c478bd9Sstevel@tonic-gate ** co_enable, thr_create() returned error = 24 6737c478bd9Sstevel@tonic-gate ** libthread panic: co_enable failed (PID: 17793 LWP 1) 6747c478bd9Sstevel@tonic-gate ** stacktrace: 6757c478bd9Sstevel@tonic-gate ** ef526b10 6767c478bd9Sstevel@tonic-gate ** ef52646c 6777c478bd9Sstevel@tonic-gate ** ef534cbc 6787c478bd9Sstevel@tonic-gate ** 156a4 6797c478bd9Sstevel@tonic-gate ** 14644 6807c478bd9Sstevel@tonic-gate ** 1413c 6817c478bd9Sstevel@tonic-gate ** 135e0 6827c478bd9Sstevel@tonic-gate ** 0 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate # define MI_SLEEP(s) \ 6867c478bd9Sstevel@tonic-gate { \ 6877c478bd9Sstevel@tonic-gate int rs = 0; \ 6887c478bd9Sstevel@tonic-gate struct timeval st; \ 6897c478bd9Sstevel@tonic-gate \ 6907c478bd9Sstevel@tonic-gate st.tv_sec = (s); \ 6917c478bd9Sstevel@tonic-gate st.tv_usec = 0; \ 6927c478bd9Sstevel@tonic-gate if (st.tv_sec > 0) \ 6937c478bd9Sstevel@tonic-gate { \ 6947c478bd9Sstevel@tonic-gate for (;;) \ 6957c478bd9Sstevel@tonic-gate { \ 6967c478bd9Sstevel@tonic-gate rs = select(0, NULL, NULL, NULL, &st); \ 6977c478bd9Sstevel@tonic-gate if (rs < 0 && errno == EINTR) \ 6987c478bd9Sstevel@tonic-gate continue; \ 6997c478bd9Sstevel@tonic-gate if (rs != 0) \ 7007c478bd9Sstevel@tonic-gate { \ 7017c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, \ 7027c478bd9Sstevel@tonic-gate "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ 7037c478bd9Sstevel@tonic-gate rs, errno); \ 7047c478bd9Sstevel@tonic-gate } \ 7057c478bd9Sstevel@tonic-gate break; \ 7067c478bd9Sstevel@tonic-gate } \ 7077c478bd9Sstevel@tonic-gate } \ 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate #else /* BROKEN_PTHREAD_SLEEP */ 7107c478bd9Sstevel@tonic-gate # define MI_SLEEP(s) sleep((s)) 7117c478bd9Sstevel@tonic-gate #endif /* BROKEN_PTHREAD_SLEEP */ 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate int 7147c478bd9Sstevel@tonic-gate mi_listener(conn, dbg, smfi, timeout, backlog) 7157c478bd9Sstevel@tonic-gate char *conn; 7167c478bd9Sstevel@tonic-gate int dbg; 7177c478bd9Sstevel@tonic-gate smfiDesc_ptr smfi; 7187c478bd9Sstevel@tonic-gate time_t timeout; 7197c478bd9Sstevel@tonic-gate int backlog; 7207c478bd9Sstevel@tonic-gate { 7217c478bd9Sstevel@tonic-gate socket_t connfd = INVALID_SOCKET; 7227c478bd9Sstevel@tonic-gate #if _FFR_DUP_FD 7237c478bd9Sstevel@tonic-gate socket_t dupfd = INVALID_SOCKET; 7247c478bd9Sstevel@tonic-gate #endif /* _FFR_DUP_FD */ 7257c478bd9Sstevel@tonic-gate int sockopt = 1; 7267c478bd9Sstevel@tonic-gate int r, mistop; 7277c478bd9Sstevel@tonic-gate int ret = MI_SUCCESS; 7287c478bd9Sstevel@tonic-gate int mcnt = 0; /* error count for malloc() failures */ 7297c478bd9Sstevel@tonic-gate int tcnt = 0; /* error count for thread_create() failures */ 7307c478bd9Sstevel@tonic-gate int acnt = 0; /* error count for accept() failures */ 7317c478bd9Sstevel@tonic-gate int scnt = 0; /* error count for select() failures */ 7327c478bd9Sstevel@tonic-gate int save_errno = 0; 733*058561cbSjbeck #if !_FFR_WORKERS_POOL 7347c478bd9Sstevel@tonic-gate sthread_t thread_id; 735*058561cbSjbeck #endif /* !_FFR_WORKERS_POOL */ 7367c478bd9Sstevel@tonic-gate _SOCK_ADDR cliaddr; 7377c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T clilen; 7387c478bd9Sstevel@tonic-gate SMFICTX_PTR ctx; 7397c478bd9Sstevel@tonic-gate FD_RD_VAR(rds, excs); 7407c478bd9Sstevel@tonic-gate struct timeval chktime; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE) 7437c478bd9Sstevel@tonic-gate return MI_FAILURE; 7447c478bd9Sstevel@tonic-gate 745*058561cbSjbeck #if _FFR_WORKERS_POOL 746*058561cbSjbeck if (mi_pool_controller_init() == MI_FAILURE) 747*058561cbSjbeck return MI_FAILURE; 748*058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 749*058561cbSjbeck 7507c478bd9Sstevel@tonic-gate clilen = L_socksize; 7517c478bd9Sstevel@tonic-gate while ((mistop = mi_stop()) == MILTER_CONT) 7527c478bd9Sstevel@tonic-gate { 7537c478bd9Sstevel@tonic-gate (void) smutex_lock(&L_Mutex); 7547c478bd9Sstevel@tonic-gate if (!ValidSocket(listenfd)) 7557c478bd9Sstevel@tonic-gate { 7567c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 7577c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 7587c478bd9Sstevel@tonic-gate "%s: listenfd=%d corrupted, terminating, errno=%d", 7597c478bd9Sstevel@tonic-gate smfi->xxfi_name, listenfd, errno); 7607c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 7617c478bd9Sstevel@tonic-gate break; 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate /* select on interface ports */ 7657c478bd9Sstevel@tonic-gate FD_RD_INIT(listenfd, rds, excs); 7667c478bd9Sstevel@tonic-gate chktime.tv_sec = MI_CHK_TIME; 7677c478bd9Sstevel@tonic-gate chktime.tv_usec = 0; 7687c478bd9Sstevel@tonic-gate r = FD_RD_READY(listenfd, rds, excs, &chktime); 7697c478bd9Sstevel@tonic-gate if (r == 0) /* timeout */ 7707c478bd9Sstevel@tonic-gate { 7717c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 7727c478bd9Sstevel@tonic-gate continue; /* just check mi_stop() */ 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate if (r < 0) 7757c478bd9Sstevel@tonic-gate { 7767c478bd9Sstevel@tonic-gate save_errno = errno; 7777c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 7787c478bd9Sstevel@tonic-gate if (save_errno == EINTR) 7797c478bd9Sstevel@tonic-gate continue; 7807c478bd9Sstevel@tonic-gate scnt++; 7817c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 7827c478bd9Sstevel@tonic-gate "%s: select() failed (%s), %s", 7837c478bd9Sstevel@tonic-gate smfi->xxfi_name, sm_errstring(save_errno), 7847c478bd9Sstevel@tonic-gate scnt >= MAX_FAILS_S ? "abort" : "try again"); 7857c478bd9Sstevel@tonic-gate MI_SLEEP(scnt); 7867c478bd9Sstevel@tonic-gate if (scnt >= MAX_FAILS_S) 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 7897c478bd9Sstevel@tonic-gate break; 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate continue; 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate if (!FD_IS_RD_RDY(listenfd, rds, excs)) 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate /* some error: just stop for now... */ 7967c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 7977c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 7987c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 7997c478bd9Sstevel@tonic-gate "%s: %s() returned exception for socket, abort", 8007c478bd9Sstevel@tonic-gate smfi->xxfi_name, MI_POLLSELECT); 8017c478bd9Sstevel@tonic-gate break; 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate scnt = 0; /* reset error counter for select() */ 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate (void) memset(&cliaddr, '\0', sizeof cliaddr); 8067c478bd9Sstevel@tonic-gate connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 8077c478bd9Sstevel@tonic-gate &clilen); 8087c478bd9Sstevel@tonic-gate save_errno = errno; 8097c478bd9Sstevel@tonic-gate (void) smutex_unlock(&L_Mutex); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* 812*058561cbSjbeck ** If remote side closes before accept() finishes, 813*058561cbSjbeck ** sockaddr might not be fully filled in. 8147c478bd9Sstevel@tonic-gate */ 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (ValidSocket(connfd) && 8177c478bd9Sstevel@tonic-gate (clilen == 0 || 8187c478bd9Sstevel@tonic-gate # ifdef BSD4_4_SOCKADDR 8197c478bd9Sstevel@tonic-gate cliaddr.sa.sa_len == 0 || 8207c478bd9Sstevel@tonic-gate # endif /* BSD4_4_SOCKADDR */ 8217c478bd9Sstevel@tonic-gate cliaddr.sa.sa_family != L_family)) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate (void) closesocket(connfd); 8247c478bd9Sstevel@tonic-gate connfd = INVALID_SOCKET; 8257c478bd9Sstevel@tonic-gate save_errno = EINVAL; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* check if acceptable for select() */ 8297c478bd9Sstevel@tonic-gate if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd)) 8307c478bd9Sstevel@tonic-gate { 8317c478bd9Sstevel@tonic-gate (void) closesocket(connfd); 8327c478bd9Sstevel@tonic-gate connfd = INVALID_SOCKET; 8337c478bd9Sstevel@tonic-gate save_errno = ERANGE; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if (!ValidSocket(connfd)) 8377c478bd9Sstevel@tonic-gate { 8387c478bd9Sstevel@tonic-gate if (save_errno == EINTR 8397c478bd9Sstevel@tonic-gate #ifdef EAGAIN 8407c478bd9Sstevel@tonic-gate || save_errno == EAGAIN 8417c478bd9Sstevel@tonic-gate #endif /* EAGAIN */ 8427c478bd9Sstevel@tonic-gate #ifdef ECONNABORTED 8437c478bd9Sstevel@tonic-gate || save_errno == ECONNABORTED 8447c478bd9Sstevel@tonic-gate #endif /* ECONNABORTED */ 8457c478bd9Sstevel@tonic-gate #ifdef EMFILE 8467c478bd9Sstevel@tonic-gate || save_errno == EMFILE 8477c478bd9Sstevel@tonic-gate #endif /* EMFILE */ 8487c478bd9Sstevel@tonic-gate #ifdef ENFILE 8497c478bd9Sstevel@tonic-gate || save_errno == ENFILE 8507c478bd9Sstevel@tonic-gate #endif /* ENFILE */ 8517c478bd9Sstevel@tonic-gate #ifdef ENOBUFS 8527c478bd9Sstevel@tonic-gate || save_errno == ENOBUFS 8537c478bd9Sstevel@tonic-gate #endif /* ENOBUFS */ 8547c478bd9Sstevel@tonic-gate #ifdef ENOMEM 8557c478bd9Sstevel@tonic-gate || save_errno == ENOMEM 8567c478bd9Sstevel@tonic-gate #endif /* ENOMEM */ 8577c478bd9Sstevel@tonic-gate #ifdef ENOSR 8587c478bd9Sstevel@tonic-gate || save_errno == ENOSR 8597c478bd9Sstevel@tonic-gate #endif /* ENOSR */ 8607c478bd9Sstevel@tonic-gate #ifdef EWOULDBLOCK 8617c478bd9Sstevel@tonic-gate || save_errno == EWOULDBLOCK 8627c478bd9Sstevel@tonic-gate #endif /* EWOULDBLOCK */ 8637c478bd9Sstevel@tonic-gate ) 8647c478bd9Sstevel@tonic-gate continue; 8657c478bd9Sstevel@tonic-gate acnt++; 8667c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 8677c478bd9Sstevel@tonic-gate "%s: accept() returned invalid socket (%s), %s", 8687c478bd9Sstevel@tonic-gate smfi->xxfi_name, sm_errstring(save_errno), 8697c478bd9Sstevel@tonic-gate acnt >= MAX_FAILS_A ? "abort" : "try again"); 8707c478bd9Sstevel@tonic-gate MI_SLEEP(acnt); 8717c478bd9Sstevel@tonic-gate if (acnt >= MAX_FAILS_A) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 8747c478bd9Sstevel@tonic-gate break; 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate continue; 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate acnt = 0; /* reset error counter for accept() */ 8797c478bd9Sstevel@tonic-gate #if _FFR_DUP_FD 8807c478bd9Sstevel@tonic-gate dupfd = fcntl(connfd, F_DUPFD, 256); 881*058561cbSjbeck if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd)) 8827c478bd9Sstevel@tonic-gate { 8837c478bd9Sstevel@tonic-gate close(connfd); 8847c478bd9Sstevel@tonic-gate connfd = dupfd; 8857c478bd9Sstevel@tonic-gate dupfd = INVALID_SOCKET; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate #endif /* _FFR_DUP_FD */ 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 8907c478bd9Sstevel@tonic-gate (void *) &sockopt, sizeof sockopt) < 0) 8917c478bd9Sstevel@tonic-gate { 892445f2479Sjbeck smi_log(SMI_LOG_WARN, 893445f2479Sjbeck "%s: set keepalive failed (%s)", 8947c478bd9Sstevel@tonic-gate smfi->xxfi_name, sm_errstring(errno)); 8957c478bd9Sstevel@tonic-gate /* XXX: continue? */ 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 8987c478bd9Sstevel@tonic-gate { 8997c478bd9Sstevel@tonic-gate (void) closesocket(connfd); 9007c478bd9Sstevel@tonic-gate mcnt++; 9017c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s", 9027c478bd9Sstevel@tonic-gate smfi->xxfi_name, sm_errstring(save_errno), 9037c478bd9Sstevel@tonic-gate mcnt >= MAX_FAILS_M ? "abort" : "try again"); 9047c478bd9Sstevel@tonic-gate MI_SLEEP(mcnt); 9057c478bd9Sstevel@tonic-gate if (mcnt >= MAX_FAILS_M) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 9087c478bd9Sstevel@tonic-gate break; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate continue; 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate mcnt = 0; /* reset error counter for malloc() */ 9137c478bd9Sstevel@tonic-gate (void) memset(ctx, '\0', sizeof *ctx); 9147c478bd9Sstevel@tonic-gate ctx->ctx_sd = connfd; 9157c478bd9Sstevel@tonic-gate ctx->ctx_dbg = dbg; 9167c478bd9Sstevel@tonic-gate ctx->ctx_timeout = timeout; 9177c478bd9Sstevel@tonic-gate ctx->ctx_smfi = smfi; 9187c478bd9Sstevel@tonic-gate if (smfi->xxfi_connect == NULL) 9197c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NOCONNECT; 9207c478bd9Sstevel@tonic-gate if (smfi->xxfi_helo == NULL) 9217c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NOHELO; 9227c478bd9Sstevel@tonic-gate if (smfi->xxfi_envfrom == NULL) 9237c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NOMAIL; 9247c478bd9Sstevel@tonic-gate if (smfi->xxfi_envrcpt == NULL) 9257c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NORCPT; 9267c478bd9Sstevel@tonic-gate if (smfi->xxfi_header == NULL) 9277c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NOHDRS; 9287c478bd9Sstevel@tonic-gate if (smfi->xxfi_eoh == NULL) 9297c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NOEOH; 9307c478bd9Sstevel@tonic-gate if (smfi->xxfi_body == NULL) 9317c478bd9Sstevel@tonic-gate ctx->ctx_pflags |= SMFIP_NOBODY; 932*058561cbSjbeck if (smfi->xxfi_data == NULL) 933*058561cbSjbeck ctx->ctx_pflags |= SMFIP_NODATA; 934*058561cbSjbeck if (smfi->xxfi_unknown == NULL) 935*058561cbSjbeck ctx->ctx_pflags |= SMFIP_NOUNKNOWN; 9367c478bd9Sstevel@tonic-gate 937*058561cbSjbeck #if _FFR_WORKERS_POOL 938*058561cbSjbeck # define LOG_CRT_FAIL "%s: mi_start_session() failed: %d, %s" 939*058561cbSjbeck if ((r = mi_start_session(ctx)) != MI_SUCCESS) 940*058561cbSjbeck #else /* _FFR_WORKERS_POOL */ 941*058561cbSjbeck # define LOG_CRT_FAIL "%s: thread_create() failed: %d, %s" 9427c478bd9Sstevel@tonic-gate if ((r = thread_create(&thread_id, 9437c478bd9Sstevel@tonic-gate mi_thread_handle_wrapper, 9447c478bd9Sstevel@tonic-gate (void *) ctx)) != 0) 945*058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 9467c478bd9Sstevel@tonic-gate { 9477c478bd9Sstevel@tonic-gate tcnt++; 9487c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 949*058561cbSjbeck LOG_CRT_FAIL, 9507c478bd9Sstevel@tonic-gate smfi->xxfi_name, r, 9517c478bd9Sstevel@tonic-gate tcnt >= MAX_FAILS_T ? "abort" : "try again"); 9527c478bd9Sstevel@tonic-gate MI_SLEEP(tcnt); 9537c478bd9Sstevel@tonic-gate (void) closesocket(connfd); 9547c478bd9Sstevel@tonic-gate free(ctx); 9557c478bd9Sstevel@tonic-gate if (tcnt >= MAX_FAILS_T) 9567c478bd9Sstevel@tonic-gate { 9577c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 9587c478bd9Sstevel@tonic-gate break; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate continue; 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate tcnt = 0; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate if (ret != MI_SUCCESS) 9657c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_ABRT); 9667c478bd9Sstevel@tonic-gate else 9677c478bd9Sstevel@tonic-gate { 9687c478bd9Sstevel@tonic-gate if (mistop != MILTER_CONT) 9697c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_INFO, "%s: mi_stop=%d", 9707c478bd9Sstevel@tonic-gate smfi->xxfi_name, mistop); 9717c478bd9Sstevel@tonic-gate mi_closener(); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate (void) smutex_destroy(&L_Mutex); 9747c478bd9Sstevel@tonic-gate return ret; 9757c478bd9Sstevel@tonic-gate } 976