2 * Copyright (c) 1999-2006 Sendmail, 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.115 2006/01/24 00:48:39 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 static smutex_t L_Mutex;
31 static SOCKADDR_LEN_T L_socksize;
32 static socket_t listenfd = INVALID_SOCKET;
34 static socket_t mi_milteropen __P((char *, int, bool, char *));
35 static void *mi_thread_handle_wrapper __P((void *));
38 ** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
41 ** conn -- connection description
42 ** backlog -- listen backlog
44 ** rmsocket -- if true, try to unlink() the socket first
45 ** (UNIX domain sockets only)
46 ** smfi -- filter structure to use
49 ** MI_SUCCESS/MI_FAILURE
53 mi_opensocket(conn, backlog, dbg, rmsocket, smfi)
60 if (smfi == NULL || conn == NULL)
63 if (ValidSocket(listenfd))
68 smi_log(SMI_LOG_DEBUG,
69 "%s: Opening listen socket on conn %s",
70 smfi->xxfi_name, conn);
72 (void) smutex_init(&L_Mutex);
73 (void) smutex_lock(&L_Mutex);
74 listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name);
75 if (!ValidSocket(listenfd))
77 smi_log(SMI_LOG_FATAL,
78 "%s: Unable to create listening socket on conn %s",
79 smfi->xxfi_name, conn);
80 (void) smutex_unlock(&L_Mutex);
84 if (!SM_FD_OK_SELECT(listenfd))
86 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
87 smfi->xxfi_name, listenfd, FD_SETSIZE);
88 (void) smutex_unlock(&L_Mutex);
91 #endif /* !SM_CONF_POLL */
92 (void) smutex_unlock(&L_Mutex);
97 ** MI_MILTEROPEN -- setup socket to listen on
100 ** conn -- connection description
101 ** backlog -- listen backlog
102 ** rmsocket -- if true, try to unlink() the socket first
103 ** (UNIX domain sockets only)
104 ** name -- name for logging
107 ** socket upon success, error code otherwise.
110 ** sets sockpath if UNIX socket.
114 static char *sockpath = NULL;
118 mi_milteropen(conn, backlog, rmsocket, name)
133 if (conn == NULL || conn[0] == '\0')
135 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
137 return INVALID_SOCKET;
139 (void) memset(&addr, '\0', sizeof addr);
141 /* protocol:filename or protocol:port@host */
143 colon = strchr(p, ':');
151 /* default to AF_UNIX */
152 addr.sa.sa_family = AF_UNIX;
153 L_socksize = sizeof (struct sockaddr_un);
156 /* default to AF_INET */
157 addr.sa.sa_family = AF_INET;
158 L_socksize = sizeof addr.sin;
161 /* default to AF_INET6 */
162 addr.sa.sa_family = AF_INET6;
163 L_socksize = sizeof addr.sin6;
164 # else /* NETINET6 */
165 /* no protocols available */
167 "%s: no valid socket protocols available",
169 return INVALID_SOCKET;
170 # endif /* NETINET6 */
171 # endif /* NETINET */
175 else if (strcasecmp(p, "unix") == 0 ||
176 strcasecmp(p, "local") == 0)
178 addr.sa.sa_family = AF_UNIX;
179 L_socksize = sizeof (struct sockaddr_un);
183 else if (strcasecmp(p, "inet") == 0)
185 addr.sa.sa_family = AF_INET;
186 L_socksize = sizeof addr.sin;
190 else if (strcasecmp(p, "inet6") == 0)
192 addr.sa.sa_family = AF_INET6;
193 L_socksize = sizeof addr.sin6;
195 #endif /* NETINET6 */
198 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
200 return INVALID_SOCKET;
208 /* default to AF_UNIX */
209 addr.sa.sa_family = AF_UNIX;
210 L_socksize = sizeof (struct sockaddr_un);
213 /* default to AF_INET */
214 addr.sa.sa_family = AF_INET;
215 L_socksize = sizeof addr.sin;
218 /* default to AF_INET6 */
219 addr.sa.sa_family = AF_INET6;
220 L_socksize = sizeof addr.sin6;
221 # else /* NETINET6 */
222 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
224 return INVALID_SOCKET;
225 # endif /* NETINET6 */
226 # endif /* NETINET */
231 if (addr.sa.sa_family == AF_UNIX)
234 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
238 len = strlen(colon) + 1;
239 if (len >= sizeof addr.sunix.sun_path)
242 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
244 return INVALID_SOCKET;
246 (void) sm_strlcpy(addr.sunix.sun_path, colon,
247 sizeof addr.sunix.sun_path);
249 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
250 S_IRUSR|S_IWUSR, NULL);
252 /* if not safe, don't create */
256 "%s: UNIX socket name %s unsafe",
258 return INVALID_SOCKET;
264 #if NETINET || NETINET6
267 addr.sa.sa_family == AF_INET
268 # endif /* NETINET */
269 # if NETINET && NETINET6
271 # endif /* NETINET && NETINET6 */
273 addr.sa.sa_family == AF_INET6
274 # endif /* NETINET6 */
279 /* Parse port@host */
280 at = strchr(colon, '@');
283 switch (addr.sa.sa_family)
287 addr.sin.sin_addr.s_addr = INADDR_ANY;
289 # endif /* NETINET */
293 addr.sin6.sin6_addr = in6addr_any;
295 # endif /* NETINET6 */
301 if (isascii(*colon) && isdigit(*colon))
302 port = htons((unsigned short) atoi(colon));
305 # ifdef NO_GETSERVBYNAME
306 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
308 return INVALID_SOCKET;
309 # else /* NO_GETSERVBYNAME */
310 register struct servent *sp;
312 sp = getservbyname(colon, "tcp");
316 "%s: unknown port name %s",
318 return INVALID_SOCKET;
321 # endif /* NO_GETSERVBYNAME */
330 end = strchr(at, ']');
335 unsigned long hid = INADDR_NONE;
336 # endif /* NETINET */
338 struct sockaddr_in6 hid6;
339 # endif /* NETINET6 */
343 if (addr.sa.sa_family == AF_INET &&
344 (hid = inet_addr(&at[1])) != INADDR_NONE)
346 addr.sin.sin_addr.s_addr = hid;
347 addr.sin.sin_port = port;
350 # endif /* NETINET */
352 (void) memset(&hid6, '\0', sizeof hid6);
353 if (addr.sa.sa_family == AF_INET6 &&
354 mi_inet_pton(AF_INET6, &at[1],
355 &hid6.sin6_addr) == 1)
357 addr.sin6.sin6_addr = hid6.sin6_addr;
358 addr.sin6.sin6_port = port;
361 # endif /* NETINET6 */
366 "%s: Invalid numeric domain spec \"%s\"",
368 return INVALID_SOCKET;
374 "%s: Invalid numeric domain spec \"%s\"",
376 return INVALID_SOCKET;
381 struct hostent *hp = NULL;
383 hp = mi_gethostbyname(at, addr.sa.sa_family);
387 "%s: Unknown host name %s",
389 return INVALID_SOCKET;
391 addr.sa.sa_family = hp->h_addrtype;
392 switch (hp->h_addrtype)
396 (void) memmove(&addr.sin.sin_addr,
399 addr.sin.sin_port = port;
401 # endif /* NETINET */
405 (void) memmove(&addr.sin6.sin6_addr,
408 addr.sin6.sin6_port = port;
410 # endif /* NETINET6 */
414 "%s: Unknown protocol for %s (%d)",
415 name, at, hp->h_addrtype);
416 return INVALID_SOCKET;
420 # endif /* NETINET6 */
425 switch (addr.sa.sa_family)
429 addr.sin.sin_port = port;
431 # endif /* NETINET */
434 addr.sin6.sin6_port = port;
436 # endif /* NETINET6 */
440 #endif /* NETINET || NETINET6 */
442 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
443 if (!ValidSocket(sock))
446 "%s: Unable to create new socket: %s",
447 name, sm_errstring(errno));
448 return INVALID_SOCKET;
451 if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
452 fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
455 "%s: Unable to set close-on-exec: %s", name,
456 sm_errstring(errno));
457 (void) closesocket(sock);
458 return INVALID_SOCKET;
463 addr.sa.sa_family != AF_UNIX &&
465 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
466 sizeof(sockopt)) == -1)
469 "%s: set reuseaddr failed (%s)", name,
470 sm_errstring(errno));
471 (void) closesocket(sock);
472 return INVALID_SOCKET;
476 if (addr.sa.sa_family == AF_UNIX && rmsocket)
480 if (stat(colon, &s) != 0)
485 "%s: Unable to stat() %s: %s",
486 name, colon, sm_errstring(errno));
487 (void) closesocket(sock);
488 return INVALID_SOCKET;
491 else if (!S_ISSOCK(s.st_mode))
494 "%s: %s is not a UNIX domain socket",
496 (void) closesocket(sock);
497 return INVALID_SOCKET;
499 else if (unlink(colon) != 0)
502 "%s: Unable to remove %s: %s",
503 name, colon, sm_errstring(errno));
504 (void) closesocket(sock);
505 return INVALID_SOCKET;
510 if (bind(sock, &addr.sa, L_socksize) < 0)
513 "%s: Unable to bind to port %s: %s",
514 name, conn, sm_errstring(errno));
515 (void) closesocket(sock);
516 return INVALID_SOCKET;
519 if (listen(sock, backlog) < 0)
522 "%s: listen call failed: %s", name,
523 sm_errstring(errno));
524 (void) closesocket(sock);
525 return INVALID_SOCKET;
529 if (addr.sa.sa_family == AF_UNIX && len > 0)
532 ** Set global variable sockpath so the UNIX socket can be
533 ** unlink()ed at exit.
536 sockpath = (char *) malloc(len);
537 if (sockpath != NULL)
538 (void) sm_strlcpy(sockpath, colon, len);
542 "%s: can't malloc(%d) for sockpath: %s",
543 name, (int) len, sm_errstring(errno));
544 (void) closesocket(sock);
545 return INVALID_SOCKET;
549 L_family = addr.sa.sa_family;
553 ** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
556 ** arg -- argument to pass to mi_handle_session()
559 ** results from mi_handle_session()
563 mi_thread_handle_wrapper(arg)
566 return (void *) mi_handle_session(arg);
570 ** MI_CLOSENER -- close listen socket
582 (void) smutex_lock(&L_Mutex);
583 if (ValidSocket(listenfd))
587 struct stat sockinfo;
588 struct stat fileinfo;
590 removable = sockpath != NULL &&
592 fstat(listenfd, &sockinfo) == 0 &&
593 (S_ISFIFO(sockinfo.st_mode)
595 || S_ISSOCK(sockinfo.st_mode)
596 # endif /* S_ISSOCK */
600 (void) closesocket(listenfd);
601 listenfd = INVALID_SOCKET;
604 /* XXX sleep() some time before doing this? */
605 if (sockpath != NULL)
608 stat(sockpath, &fileinfo) == 0 &&
609 ((fileinfo.st_dev == sockinfo.st_dev &&
610 fileinfo.st_ino == sockinfo.st_ino)
612 || S_ISSOCK(fileinfo.st_mode)
613 # endif /* S_ISSOCK */
616 (S_ISFIFO(fileinfo.st_mode)
618 || S_ISSOCK(fileinfo.st_mode)
619 # endif /* S_ISSOCK */
621 (void) unlink(sockpath);
627 (void) smutex_unlock(&L_Mutex);
631 ** MI_LISTENER -- Generic listener harness
633 ** Open up listen port
634 ** Wait for connections
637 ** conn -- connection description
638 ** dbg -- debug level
639 ** smfi -- filter structure to use
640 ** timeout -- timeout for reads/writes
641 ** backlog -- listen queue backlog size
644 ** MI_SUCCESS -- Exited normally
645 ** (session finished or we were told to exit)
646 ** MI_FAILURE -- Network initialization failed.
649 #if BROKEN_PTHREAD_SLEEP
652 ** Solaris 2.6, perhaps others, gets an internal threads library panic
653 ** when sleep() is used:
655 ** thread_create() failed, returned 11 (EINVAL)
656 ** co_enable, thr_create() returned error = 24
657 ** libthread panic: co_enable failed (PID: 17793 LWP 1)
669 # define MI_SLEEP(s) \
680 rs = select(0, NULL, NULL, NULL, &st); \
681 if (rs < 0 && errno == EINTR) \
685 smi_log(SMI_LOG_ERR, \
686 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
693 #else /* BROKEN_PTHREAD_SLEEP */
694 # define MI_SLEEP(s) sleep((s))
695 #endif /* BROKEN_PTHREAD_SLEEP */
698 mi_listener(conn, dbg, smfi, timeout, backlog)
705 socket_t connfd = INVALID_SOCKET;
707 socket_t dupfd = INVALID_SOCKET;
708 #endif /* _FFR_DUP_FD */
711 int ret = MI_SUCCESS;
712 int mcnt = 0; /* error count for malloc() failures */
713 int tcnt = 0; /* error count for thread_create() failures */
714 int acnt = 0; /* error count for accept() failures */
715 int scnt = 0; /* error count for select() failures */
719 SOCKADDR_LEN_T clilen;
721 FD_RD_VAR(rds, excs);
722 struct timeval chktime;
724 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
728 while ((mistop = mi_stop()) == MILTER_CONT)
730 (void) smutex_lock(&L_Mutex);
731 if (!ValidSocket(listenfd))
735 "%s: listenfd=%d corrupted, terminating, errno=%d",
736 smfi->xxfi_name, listenfd, errno);
737 (void) smutex_unlock(&L_Mutex);
741 /* select on interface ports */
742 FD_RD_INIT(listenfd, rds, excs);
743 chktime.tv_sec = MI_CHK_TIME;
745 r = FD_RD_READY(listenfd, rds, excs, &chktime);
746 if (r == 0) /* timeout */
748 (void) smutex_unlock(&L_Mutex);
749 continue; /* just check mi_stop() */
754 (void) smutex_unlock(&L_Mutex);
755 if (save_errno == EINTR)
759 "%s: select() failed (%s), %s",
760 smfi->xxfi_name, sm_errstring(save_errno),
761 scnt >= MAX_FAILS_S ? "abort" : "try again");
763 if (scnt >= MAX_FAILS_S)
770 if (!FD_IS_RD_RDY(listenfd, rds, excs))
772 /* some error: just stop for now... */
774 (void) smutex_unlock(&L_Mutex);
776 "%s: %s() returned exception for socket, abort",
777 smfi->xxfi_name, MI_POLLSELECT);
780 scnt = 0; /* reset error counter for select() */
782 (void) memset(&cliaddr, '\0', sizeof cliaddr);
783 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
786 (void) smutex_unlock(&L_Mutex);
789 ** If remote side closes before
790 ** accept() finishes, sockaddr
791 ** might not be fully filled in.
794 if (ValidSocket(connfd) &&
796 # ifdef BSD4_4_SOCKADDR
797 cliaddr.sa.sa_len == 0 ||
798 # endif /* BSD4_4_SOCKADDR */
799 cliaddr.sa.sa_family != L_family))
801 (void) closesocket(connfd);
802 connfd = INVALID_SOCKET;
807 /* check if acceptable for select() */
808 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
810 (void) closesocket(connfd);
811 connfd = INVALID_SOCKET;
814 #endif /* !SM_CONF_POLL */
816 if (!ValidSocket(connfd))
818 if (save_errno == EINTR
820 || save_errno == EAGAIN
823 || save_errno == ECONNABORTED
824 #endif /* ECONNABORTED */
826 || save_errno == EMFILE
829 || save_errno == ENFILE
832 || save_errno == ENOBUFS
835 || save_errno == ENOMEM
838 || save_errno == ENOSR
841 || save_errno == EWOULDBLOCK
842 #endif /* EWOULDBLOCK */
847 "%s: accept() returned invalid socket (%s), %s",
848 smfi->xxfi_name, sm_errstring(save_errno),
849 acnt >= MAX_FAILS_A ? "abort" : "try again");
851 if (acnt >= MAX_FAILS_A)
858 acnt = 0; /* reset error counter for accept() */
860 dupfd = fcntl(connfd, F_DUPFD, 256);
861 if (ValidSocket(dupfd)
863 && SM_FD_OK_SELECT(dupfd)
864 # endif /* !SM_CONF_POLL */
869 dupfd = INVALID_SOCKET;
871 #endif /* _FFR_DUP_FD */
873 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
874 (void *) &sockopt, sizeof sockopt) < 0)
876 smi_log(SMI_LOG_WARN,
877 "%s: set keepalive failed (%s)",
878 smfi->xxfi_name, sm_errstring(errno));
881 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
883 (void) closesocket(connfd);
885 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
886 smfi->xxfi_name, sm_errstring(save_errno),
887 mcnt >= MAX_FAILS_M ? "abort" : "try again");
889 if (mcnt >= MAX_FAILS_M)
896 mcnt = 0; /* reset error counter for malloc() */
897 (void) memset(ctx, '\0', sizeof *ctx);
898 ctx->ctx_sd = connfd;
900 ctx->ctx_timeout = timeout;
901 ctx->ctx_smfi = smfi;
903 if (smfi->xxfi_eoh == NULL)
904 if (smfi->xxfi_eom == NULL)
905 if (smfi->xxfi_abort == NULL)
906 if (smfi->xxfi_close == NULL)
908 if (smfi->xxfi_connect == NULL)
909 ctx->ctx_pflags |= SMFIP_NOCONNECT;
910 if (smfi->xxfi_helo == NULL)
911 ctx->ctx_pflags |= SMFIP_NOHELO;
912 if (smfi->xxfi_envfrom == NULL)
913 ctx->ctx_pflags |= SMFIP_NOMAIL;
914 if (smfi->xxfi_envrcpt == NULL)
915 ctx->ctx_pflags |= SMFIP_NORCPT;
916 if (smfi->xxfi_header == NULL)
917 ctx->ctx_pflags |= SMFIP_NOHDRS;
918 if (smfi->xxfi_eoh == NULL)
919 ctx->ctx_pflags |= SMFIP_NOEOH;
920 if (smfi->xxfi_body == NULL)
921 ctx->ctx_pflags |= SMFIP_NOBODY;
923 if ((r = thread_create(&thread_id,
924 mi_thread_handle_wrapper,
929 "%s: thread_create() failed: %d, %s",
931 tcnt >= MAX_FAILS_T ? "abort" : "try again");
933 (void) closesocket(connfd);
935 if (tcnt >= MAX_FAILS_T)
944 if (ret != MI_SUCCESS)
945 mi_stop_milters(MILTER_ABRT);
948 if (mistop != MILTER_CONT)
949 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
950 smfi->xxfi_name, mistop);
953 (void) smutex_destroy(&L_Mutex);