2 * Copyright (c) 1999-2007 Proofpoint, Inc. and its suppliers.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
12 SM_RCSID("@(#)$Id: listener.c,v 8.127 2013-11-22 20:51:36 ca Exp $")
15 ** listener.c -- threaded network listener
18 #include "libmilter.h"
19 #include <sm/errstring.h>
21 #include <sys/types.h>
25 # if NETINET || NETINET6
26 # include <arpa/inet.h>
27 # endif /* NETINET || NETINET6 */
29 # undef SM_FD_OK_SELECT
30 # define SM_FD_OK_SELECT(fd) true
31 # endif /* SM_CONF_POLL */
33 static smutex_t L_Mutex;
35 static SOCKADDR_LEN_T L_socksize;
36 static socket_t listenfd = INVALID_SOCKET;
38 static socket_t mi_milteropen __P((char *, int, bool, char *));
39 #if !_FFR_WORKERS_POOL
40 static void *mi_thread_handle_wrapper __P((void *));
41 #endif /* !_FFR_WORKERS_POOL */
44 ** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
47 ** conn -- connection description
48 ** backlog -- listen backlog
50 ** rmsocket -- if true, try to unlink() the socket first
51 ** (UNIX domain sockets only)
52 ** smfi -- filter structure to use
55 ** MI_SUCCESS/MI_FAILURE
59 mi_opensocket(conn, backlog, dbg, rmsocket, smfi)
66 if (smfi == NULL || conn == NULL)
69 if (ValidSocket(listenfd))
74 smi_log(SMI_LOG_DEBUG,
75 "%s: Opening listen socket on conn %s",
76 smfi->xxfi_name, conn);
78 (void) smutex_init(&L_Mutex);
79 (void) smutex_lock(&L_Mutex);
80 listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name);
81 if (!ValidSocket(listenfd))
83 smi_log(SMI_LOG_FATAL,
84 "%s: Unable to create listening socket on conn %s",
85 smfi->xxfi_name, conn);
86 (void) smutex_unlock(&L_Mutex);
89 if (!SM_FD_OK_SELECT(listenfd))
91 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
92 smfi->xxfi_name, listenfd, FD_SETSIZE);
93 (void) smutex_unlock(&L_Mutex);
96 (void) smutex_unlock(&L_Mutex);
101 ** MI_MILTEROPEN -- setup socket to listen on
104 ** conn -- connection description
105 ** backlog -- listen backlog
106 ** rmsocket -- if true, try to unlink() the socket first
107 ** (UNIX domain sockets only)
108 ** name -- name for logging
111 ** socket upon success, error code otherwise.
114 ** sets sockpath if UNIX socket.
118 static char *sockpath = NULL;
122 mi_milteropen(conn, backlog, rmsocket, name)
137 if (conn == NULL || conn[0] == '\0')
139 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
141 return INVALID_SOCKET;
143 (void) memset(&addr, '\0', sizeof addr);
145 /* protocol:filename or protocol:port@host */
147 colon = strchr(p, ':');
155 /* default to AF_UNIX */
156 addr.sa.sa_family = AF_UNIX;
157 L_socksize = sizeof (struct sockaddr_un);
160 /* default to AF_INET */
161 addr.sa.sa_family = AF_INET;
162 L_socksize = sizeof addr.sin;
165 /* default to AF_INET6 */
166 addr.sa.sa_family = AF_INET6;
167 L_socksize = sizeof addr.sin6;
168 # else /* NETINET6 */
169 /* no protocols available */
171 "%s: no valid socket protocols available",
173 return INVALID_SOCKET;
174 # endif /* NETINET6 */
175 # endif /* NETINET */
179 else if (strcasecmp(p, "unix") == 0 ||
180 strcasecmp(p, "local") == 0)
182 addr.sa.sa_family = AF_UNIX;
183 L_socksize = sizeof (struct sockaddr_un);
187 else if (strcasecmp(p, "inet") == 0)
189 addr.sa.sa_family = AF_INET;
190 L_socksize = sizeof addr.sin;
194 else if (strcasecmp(p, "inet6") == 0)
196 addr.sa.sa_family = AF_INET6;
197 L_socksize = sizeof addr.sin6;
199 #endif /* NETINET6 */
202 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
204 return INVALID_SOCKET;
212 /* default to AF_UNIX */
213 addr.sa.sa_family = AF_UNIX;
214 L_socksize = sizeof (struct sockaddr_un);
217 /* default to AF_INET */
218 addr.sa.sa_family = AF_INET;
219 L_socksize = sizeof addr.sin;
222 /* default to AF_INET6 */
223 addr.sa.sa_family = AF_INET6;
224 L_socksize = sizeof addr.sin6;
225 # else /* NETINET6 */
226 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
228 return INVALID_SOCKET;
229 # endif /* NETINET6 */
230 # endif /* NETINET */
235 if (addr.sa.sa_family == AF_UNIX)
238 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
242 len = strlen(colon) + 1;
243 if (len >= sizeof addr.sunix.sun_path)
246 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
248 return INVALID_SOCKET;
250 (void) sm_strlcpy(addr.sunix.sun_path, colon,
251 sizeof addr.sunix.sun_path);
253 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
254 S_IRUSR|S_IWUSR, NULL);
256 /* if not safe, don't create */
260 "%s: UNIX socket name %s unsafe",
262 return INVALID_SOCKET;
268 #if NETINET || NETINET6
271 addr.sa.sa_family == AF_INET
272 # endif /* NETINET */
273 # if NETINET && NETINET6
275 # endif /* NETINET && NETINET6 */
277 addr.sa.sa_family == AF_INET6
278 # endif /* NETINET6 */
283 /* Parse port@host */
284 at = strchr(colon, '@');
287 switch (addr.sa.sa_family)
291 addr.sin.sin_addr.s_addr = INADDR_ANY;
293 # endif /* NETINET */
297 addr.sin6.sin6_addr = in6addr_any;
299 # endif /* NETINET6 */
305 if (isascii(*colon) && isdigit(*colon))
306 port = htons((unsigned short) atoi(colon));
309 # ifdef NO_GETSERVBYNAME
310 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
312 return INVALID_SOCKET;
313 # else /* NO_GETSERVBYNAME */
314 register struct servent *sp;
316 sp = getservbyname(colon, "tcp");
320 "%s: unknown port name %s",
322 return INVALID_SOCKET;
325 # endif /* NO_GETSERVBYNAME */
334 end = strchr(at, ']');
339 unsigned long hid = INADDR_NONE;
340 # endif /* NETINET */
342 struct sockaddr_in6 hid6;
343 # endif /* NETINET6 */
347 if (addr.sa.sa_family == AF_INET &&
348 (hid = inet_addr(&at[1])) != INADDR_NONE)
350 addr.sin.sin_addr.s_addr = hid;
351 addr.sin.sin_port = port;
354 # endif /* NETINET */
356 (void) memset(&hid6, '\0', sizeof hid6);
357 if (addr.sa.sa_family == AF_INET6 &&
358 mi_inet_pton(AF_INET6, &at[1],
359 &hid6.sin6_addr) == 1)
361 addr.sin6.sin6_addr = hid6.sin6_addr;
362 addr.sin6.sin6_port = port;
365 # endif /* NETINET6 */
370 "%s: Invalid numeric domain spec \"%s\"",
372 return INVALID_SOCKET;
378 "%s: Invalid numeric domain spec \"%s\"",
380 return INVALID_SOCKET;
385 struct hostent *hp = NULL;
387 hp = mi_gethostbyname(at, addr.sa.sa_family);
391 "%s: Unknown host name %s",
393 return INVALID_SOCKET;
395 addr.sa.sa_family = hp->h_addrtype;
396 switch (hp->h_addrtype)
400 (void) memmove(&addr.sin.sin_addr,
403 addr.sin.sin_port = port;
405 # endif /* NETINET */
409 (void) memmove(&addr.sin6.sin6_addr,
412 addr.sin6.sin6_port = port;
414 # endif /* NETINET6 */
418 "%s: Unknown protocol for %s (%d)",
419 name, at, hp->h_addrtype);
420 return INVALID_SOCKET;
424 # endif /* NETINET6 */
429 switch (addr.sa.sa_family)
433 addr.sin.sin_port = port;
435 # endif /* NETINET */
438 addr.sin6.sin6_port = port;
440 # endif /* NETINET6 */
444 #endif /* NETINET || NETINET6 */
446 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
447 if (!ValidSocket(sock))
450 "%s: Unable to create new socket: %s",
451 name, sm_errstring(errno));
452 return INVALID_SOCKET;
455 if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
456 fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
459 "%s: Unable to set close-on-exec: %s", name,
460 sm_errstring(errno));
461 (void) closesocket(sock);
462 return INVALID_SOCKET;
467 addr.sa.sa_family != AF_UNIX &&
469 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
470 sizeof(sockopt)) == -1)
473 "%s: set reuseaddr failed (%s)", name,
474 sm_errstring(errno));
475 (void) closesocket(sock);
476 return INVALID_SOCKET;
480 if (addr.sa.sa_family == AF_UNIX && rmsocket)
484 if (stat(colon, &s) != 0)
489 "%s: Unable to stat() %s: %s",
490 name, colon, sm_errstring(errno));
491 (void) closesocket(sock);
492 return INVALID_SOCKET;
495 else if (!S_ISSOCK(s.st_mode))
498 "%s: %s is not a UNIX domain socket",
500 (void) closesocket(sock);
501 return INVALID_SOCKET;
503 else if (unlink(colon) != 0)
506 "%s: Unable to remove %s: %s",
507 name, colon, sm_errstring(errno));
508 (void) closesocket(sock);
509 return INVALID_SOCKET;
514 if (bind(sock, &addr.sa, L_socksize) < 0)
517 "%s: Unable to bind to port %s: %s",
518 name, conn, sm_errstring(errno));
519 (void) closesocket(sock);
520 return INVALID_SOCKET;
523 if (listen(sock, backlog) < 0)
526 "%s: listen call failed: %s", name,
527 sm_errstring(errno));
528 (void) closesocket(sock);
529 return INVALID_SOCKET;
533 if (addr.sa.sa_family == AF_UNIX && len > 0)
536 ** Set global variable sockpath so the UNIX socket can be
537 ** unlink()ed at exit.
540 sockpath = (char *) malloc(len);
541 if (sockpath != NULL)
542 (void) sm_strlcpy(sockpath, colon, len);
546 "%s: can't malloc(%d) for sockpath: %s",
547 name, (int) len, sm_errstring(errno));
548 (void) closesocket(sock);
549 return INVALID_SOCKET;
553 L_family = addr.sa.sa_family;
557 #if !_FFR_WORKERS_POOL
559 ** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
562 ** arg -- argument to pass to mi_handle_session()
565 ** results from mi_handle_session()
569 mi_thread_handle_wrapper(arg)
573 ** Note: on some systems this generates a compiler warning:
574 ** cast to pointer from integer of different size
575 ** You can safely ignore this warning as the result of this function
576 ** is not used anywhere.
579 return (void *) mi_handle_session(arg);
581 #endif /* _FFR_WORKERS_POOL */
584 ** MI_CLOSENER -- close listen socket
596 (void) smutex_lock(&L_Mutex);
597 if (ValidSocket(listenfd))
601 struct stat sockinfo;
602 struct stat fileinfo;
604 removable = sockpath != NULL &&
606 fstat(listenfd, &sockinfo) == 0 &&
607 (S_ISFIFO(sockinfo.st_mode)
609 || S_ISSOCK(sockinfo.st_mode)
610 # endif /* S_ISSOCK */
614 (void) closesocket(listenfd);
615 listenfd = INVALID_SOCKET;
618 /* XXX sleep() some time before doing this? */
619 if (sockpath != NULL)
622 stat(sockpath, &fileinfo) == 0 &&
623 ((fileinfo.st_dev == sockinfo.st_dev &&
624 fileinfo.st_ino == sockinfo.st_ino)
626 || S_ISSOCK(fileinfo.st_mode)
627 # endif /* S_ISSOCK */
630 (S_ISFIFO(fileinfo.st_mode)
632 || S_ISSOCK(fileinfo.st_mode)
633 # endif /* S_ISSOCK */
635 (void) unlink(sockpath);
641 (void) smutex_unlock(&L_Mutex);
645 ** MI_LISTENER -- Generic listener harness
647 ** Open up listen port
648 ** Wait for connections
651 ** conn -- connection description
652 ** dbg -- debug level
653 ** smfi -- filter structure to use
654 ** timeout -- timeout for reads/writes
655 ** backlog -- listen queue backlog size
658 ** MI_SUCCESS -- Exited normally
659 ** (session finished or we were told to exit)
660 ** MI_FAILURE -- Network initialization failed.
663 #if BROKEN_PTHREAD_SLEEP
666 ** Solaris 2.6, perhaps others, gets an internal threads library panic
667 ** when sleep() is used:
669 ** thread_create() failed, returned 11 (EINVAL)
670 ** co_enable, thr_create() returned error = 24
671 ** libthread panic: co_enable failed (PID: 17793 LWP 1)
683 # define MI_SLEEP(s) \
694 rs = select(0, NULL, NULL, NULL, &st); \
695 if (rs < 0 && errno == EINTR) \
699 smi_log(SMI_LOG_ERR, \
700 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
707 #else /* BROKEN_PTHREAD_SLEEP */
708 # define MI_SLEEP(s) sleep((s))
709 #endif /* BROKEN_PTHREAD_SLEEP */
712 mi_listener(conn, dbg, smfi, timeout, backlog)
719 socket_t connfd = INVALID_SOCKET;
721 socket_t dupfd = INVALID_SOCKET;
722 #endif /* _FFR_DUP_FD */
725 int ret = MI_SUCCESS;
726 int mcnt = 0; /* error count for malloc() failures */
727 int tcnt = 0; /* error count for thread_create() failures */
728 int acnt = 0; /* error count for accept() failures */
729 int scnt = 0; /* error count for select() failures */
732 #if !_FFR_WORKERS_POOL
734 #endif /* !_FFR_WORKERS_POOL */
736 SOCKADDR_LEN_T clilen;
738 FD_RD_VAR(rds, excs);
739 struct timeval chktime;
741 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
744 #if _FFR_WORKERS_POOL
745 if (mi_pool_controller_init() == MI_FAILURE)
747 #endif /* _FFR_WORKERS_POOL */
750 while ((mistop = mi_stop()) == MILTER_CONT)
752 (void) smutex_lock(&L_Mutex);
753 if (!ValidSocket(listenfd))
757 "%s: listenfd=%d corrupted, terminating, errno=%d",
758 smfi->xxfi_name, listenfd, errno);
759 (void) smutex_unlock(&L_Mutex);
763 /* select on interface ports */
764 FD_RD_INIT(listenfd, rds, excs);
765 chktime.tv_sec = MI_CHK_TIME;
767 r = FD_RD_READY(listenfd, rds, excs, &chktime);
768 if (r == 0) /* timeout */
770 (void) smutex_unlock(&L_Mutex);
771 continue; /* just check mi_stop() */
776 (void) smutex_unlock(&L_Mutex);
777 if (save_errno == EINTR)
781 "%s: %s() failed (%s), %s",
782 smfi->xxfi_name, MI_POLLSELECT,
783 sm_errstring(save_errno),
784 scnt >= MAX_FAILS_S ? "abort" : "try again");
786 if (scnt >= MAX_FAILS_S)
793 if (!FD_IS_RD_RDY(listenfd, rds, excs))
795 /* some error: just stop for now... */
797 (void) smutex_unlock(&L_Mutex);
799 "%s: %s() returned exception for socket, abort",
800 smfi->xxfi_name, MI_POLLSELECT);
803 scnt = 0; /* reset error counter for select() */
805 (void) memset(&cliaddr, '\0', sizeof cliaddr);
806 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
809 (void) smutex_unlock(&L_Mutex);
812 ** If remote side closes before accept() finishes,
813 ** sockaddr might not be fully filled in.
816 if (ValidSocket(connfd) &&
818 # ifdef BSD4_4_SOCKADDR
819 cliaddr.sa.sa_len == 0 ||
820 # endif /* BSD4_4_SOCKADDR */
821 cliaddr.sa.sa_family != L_family))
823 (void) closesocket(connfd);
824 connfd = INVALID_SOCKET;
828 /* check if acceptable for select() */
829 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
831 (void) closesocket(connfd);
832 connfd = INVALID_SOCKET;
836 if (!ValidSocket(connfd))
838 if (save_errno == EINTR
840 || save_errno == EAGAIN
843 || save_errno == ECONNABORTED
844 #endif /* ECONNABORTED */
846 || save_errno == EMFILE
849 || save_errno == ENFILE
852 || save_errno == ENOBUFS
855 || save_errno == ENOMEM
858 || save_errno == ENOSR
861 || save_errno == EWOULDBLOCK
862 #endif /* EWOULDBLOCK */
867 "%s: accept() returned invalid socket (%s), %s",
868 smfi->xxfi_name, sm_errstring(save_errno),
869 acnt >= MAX_FAILS_A ? "abort" : "try again");
871 if (acnt >= MAX_FAILS_A)
878 acnt = 0; /* reset error counter for accept() */
880 dupfd = fcntl(connfd, F_DUPFD, 256);
881 if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd))
885 dupfd = INVALID_SOCKET;
887 #endif /* _FFR_DUP_FD */
890 ** Need to set close-on-exec for connfd in case a user's
891 ** filter starts other applications.
892 ** Note: errors will not stop processing (for now).
895 if ((fdflags = fcntl(connfd, F_GETFD, 0)) == -1 ||
896 fcntl(connfd, F_SETFD, fdflags | FD_CLOEXEC) == -1)
899 "%s: Unable to set close-on-exec: %s",
900 smfi->xxfi_name, sm_errstring(errno));
903 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
904 (void *) &sockopt, sizeof sockopt) < 0)
906 smi_log(SMI_LOG_WARN,
907 "%s: set keepalive failed (%s)",
908 smfi->xxfi_name, sm_errstring(errno));
911 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
913 (void) closesocket(connfd);
915 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
916 smfi->xxfi_name, sm_errstring(save_errno),
917 mcnt >= MAX_FAILS_M ? "abort" : "try again");
919 if (mcnt >= MAX_FAILS_M)
926 mcnt = 0; /* reset error counter for malloc() */
927 (void) memset(ctx, '\0', sizeof *ctx);
928 ctx->ctx_sd = connfd;
930 ctx->ctx_timeout = timeout;
931 ctx->ctx_smfi = smfi;
932 if (smfi->xxfi_connect == NULL)
933 ctx->ctx_pflags |= SMFIP_NOCONNECT;
934 if (smfi->xxfi_helo == NULL)
935 ctx->ctx_pflags |= SMFIP_NOHELO;
936 if (smfi->xxfi_envfrom == NULL)
937 ctx->ctx_pflags |= SMFIP_NOMAIL;
938 if (smfi->xxfi_envrcpt == NULL)
939 ctx->ctx_pflags |= SMFIP_NORCPT;
940 if (smfi->xxfi_header == NULL)
941 ctx->ctx_pflags |= SMFIP_NOHDRS;
942 if (smfi->xxfi_eoh == NULL)
943 ctx->ctx_pflags |= SMFIP_NOEOH;
944 if (smfi->xxfi_body == NULL)
945 ctx->ctx_pflags |= SMFIP_NOBODY;
946 if (smfi->xxfi_version <= 3 || smfi->xxfi_data == NULL)
947 ctx->ctx_pflags |= SMFIP_NODATA;
948 if (smfi->xxfi_version <= 2 || smfi->xxfi_unknown == NULL)
949 ctx->ctx_pflags |= SMFIP_NOUNKNOWN;
951 #if _FFR_WORKERS_POOL
952 # define LOG_CRT_FAIL "%s: mi_start_session() failed: %d, %s"
953 if ((r = mi_start_session(ctx)) != MI_SUCCESS)
954 #else /* _FFR_WORKERS_POOL */
955 # define LOG_CRT_FAIL "%s: thread_create() failed: %d, %s"
956 if ((r = thread_create(&thread_id,
957 mi_thread_handle_wrapper,
959 #endif /* _FFR_WORKERS_POOL */
965 tcnt >= MAX_FAILS_T ? "abort" : "try again");
967 (void) closesocket(connfd);
969 if (tcnt >= MAX_FAILS_T)
978 if (ret != MI_SUCCESS)
979 mi_stop_milters(MILTER_ABRT);
982 if (mistop != MILTER_CONT)
983 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
984 smfi->xxfi_name, mistop);
987 (void) smutex_destroy(&L_Mutex);