2 * Copyright (c) 1999-2004 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.111 2004/09/20 21:11:15 msk 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;
461 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
462 sizeof(sockopt)) == -1)
465 "%s: Unable to setsockopt: %s", name,
466 sm_errstring(errno));
467 (void) closesocket(sock);
468 return INVALID_SOCKET;
472 if (addr.sa.sa_family == AF_UNIX && rmsocket)
476 if (stat(colon, &s) != 0)
481 "%s: Unable to stat() %s: %s",
482 name, colon, sm_errstring(errno));
483 (void) closesocket(sock);
484 return INVALID_SOCKET;
487 else if (!S_ISSOCK(s.st_mode))
490 "%s: %s is not a UNIX domain socket",
492 (void) closesocket(sock);
493 return INVALID_SOCKET;
495 else if (unlink(colon) != 0)
498 "%s: Unable to remove %s: %s",
499 name, colon, sm_errstring(errno));
500 (void) closesocket(sock);
501 return INVALID_SOCKET;
506 if (bind(sock, &addr.sa, L_socksize) < 0)
509 "%s: Unable to bind to port %s: %s",
510 name, conn, sm_errstring(errno));
511 (void) closesocket(sock);
512 return INVALID_SOCKET;
515 if (listen(sock, backlog) < 0)
518 "%s: listen call failed: %s", name,
519 sm_errstring(errno));
520 (void) closesocket(sock);
521 return INVALID_SOCKET;
525 if (addr.sa.sa_family == AF_UNIX && len > 0)
528 ** Set global variable sockpath so the UNIX socket can be
529 ** unlink()ed at exit.
532 sockpath = (char *) malloc(len);
533 if (sockpath != NULL)
534 (void) sm_strlcpy(sockpath, colon, len);
538 "%s: can't malloc(%d) for sockpath: %s",
539 name, (int) len, sm_errstring(errno));
540 (void) closesocket(sock);
541 return INVALID_SOCKET;
545 L_family = addr.sa.sa_family;
549 ** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
552 ** arg -- argument to pass to mi_handle_session()
555 ** results from mi_handle_session()
559 mi_thread_handle_wrapper(arg)
562 return (void *) mi_handle_session(arg);
566 ** MI_CLOSENER -- close listen socket
568 ** NOTE: It is assumed that this function is called from a
569 ** function that has a mutex lock (currently mi_stop_milters()).
581 (void) smutex_lock(&L_Mutex);
582 if (ValidSocket(listenfd))
586 struct stat sockinfo;
587 struct stat fileinfo;
589 removable = sockpath != NULL &&
591 fstat(listenfd, &sockinfo) == 0 &&
592 (S_ISFIFO(sockinfo.st_mode)
594 || S_ISSOCK(sockinfo.st_mode)
595 # endif /* S_ISSOCK */
599 (void) closesocket(listenfd);
600 listenfd = INVALID_SOCKET;
603 /* XXX sleep() some time before doing this? */
604 if (sockpath != NULL)
607 stat(sockpath, &fileinfo) == 0 &&
608 ((fileinfo.st_dev == sockinfo.st_dev &&
609 fileinfo.st_ino == sockinfo.st_ino)
611 || S_ISSOCK(fileinfo.st_mode)
612 # endif /* S_ISSOCK */
615 (S_ISFIFO(fileinfo.st_mode)
617 || S_ISSOCK(fileinfo.st_mode)
618 # endif /* S_ISSOCK */
620 (void) unlink(sockpath);
626 (void) smutex_unlock(&L_Mutex);
630 ** MI_LISTENER -- Generic listener harness
632 ** Open up listen port
633 ** Wait for connections
636 ** conn -- connection description
637 ** dbg -- debug level
638 ** smfi -- filter structure to use
639 ** timeout -- timeout for reads/writes
640 ** backlog -- listen queue backlog size
643 ** MI_SUCCESS -- Exited normally
644 ** (session finished or we were told to exit)
645 ** MI_FAILURE -- Network initialization failed.
648 #if BROKEN_PTHREAD_SLEEP
651 ** Solaris 2.6, perhaps others, gets an internal threads library panic
652 ** when sleep() is used:
654 ** thread_create() failed, returned 11 (EINVAL)
655 ** co_enable, thr_create() returned error = 24
656 ** libthread panic: co_enable failed (PID: 17793 LWP 1)
668 # define MI_SLEEP(s) \
679 rs = select(0, NULL, NULL, NULL, &st); \
680 if (rs < 0 && errno == EINTR) \
684 smi_log(SMI_LOG_ERR, \
685 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
692 #else /* BROKEN_PTHREAD_SLEEP */
693 # define MI_SLEEP(s) sleep((s))
694 #endif /* BROKEN_PTHREAD_SLEEP */
697 mi_listener(conn, dbg, smfi, timeout, backlog)
704 socket_t connfd = INVALID_SOCKET;
706 socket_t dupfd = INVALID_SOCKET;
707 #endif /* _FFR_DUP_FD */
710 int ret = MI_SUCCESS;
711 int mcnt = 0; /* error count for malloc() failures */
712 int tcnt = 0; /* error count for thread_create() failures */
713 int acnt = 0; /* error count for accept() failures */
714 int scnt = 0; /* error count for select() failures */
718 SOCKADDR_LEN_T clilen;
720 FD_RD_VAR(rds, excs);
721 struct timeval chktime;
723 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
727 while ((mistop = mi_stop()) == MILTER_CONT)
729 (void) smutex_lock(&L_Mutex);
730 if (!ValidSocket(listenfd))
734 "%s: listenfd=%d corrupted, terminating, errno=%d",
735 smfi->xxfi_name, listenfd, errno);
736 (void) smutex_unlock(&L_Mutex);
740 /* select on interface ports */
741 FD_RD_INIT(listenfd, rds, excs);
742 chktime.tv_sec = MI_CHK_TIME;
744 r = FD_RD_READY(listenfd, rds, excs, &chktime);
745 if (r == 0) /* timeout */
747 (void) smutex_unlock(&L_Mutex);
748 continue; /* just check mi_stop() */
753 (void) smutex_unlock(&L_Mutex);
754 if (save_errno == EINTR)
758 "%s: select() failed (%s), %s",
759 smfi->xxfi_name, sm_errstring(save_errno),
760 scnt >= MAX_FAILS_S ? "abort" : "try again");
762 if (scnt >= MAX_FAILS_S)
769 if (!FD_IS_RD_RDY(listenfd, rds, excs))
771 /* some error: just stop for now... */
773 (void) smutex_unlock(&L_Mutex);
775 "%s: %s() returned exception for socket, abort",
776 smfi->xxfi_name, MI_POLLSELECT);
779 scnt = 0; /* reset error counter for select() */
781 (void) memset(&cliaddr, '\0', sizeof cliaddr);
782 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
785 (void) smutex_unlock(&L_Mutex);
788 ** If remote side closes before
789 ** accept() finishes, sockaddr
790 ** might not be fully filled in.
793 if (ValidSocket(connfd) &&
795 # ifdef BSD4_4_SOCKADDR
796 cliaddr.sa.sa_len == 0 ||
797 # endif /* BSD4_4_SOCKADDR */
798 cliaddr.sa.sa_family != L_family))
800 (void) closesocket(connfd);
801 connfd = INVALID_SOCKET;
806 /* check if acceptable for select() */
807 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
809 (void) closesocket(connfd);
810 connfd = INVALID_SOCKET;
813 #endif /* !SM_CONF_POLL */
815 if (!ValidSocket(connfd))
817 if (save_errno == EINTR
819 || save_errno == EAGAIN
822 || save_errno == ECONNABORTED
823 #endif /* ECONNABORTED */
825 || save_errno == EMFILE
828 || save_errno == ENFILE
831 || save_errno == ENOBUFS
834 || save_errno == ENOMEM
837 || save_errno == ENOSR
840 || save_errno == EWOULDBLOCK
841 #endif /* EWOULDBLOCK */
846 "%s: accept() returned invalid socket (%s), %s",
847 smfi->xxfi_name, sm_errstring(save_errno),
848 acnt >= MAX_FAILS_A ? "abort" : "try again");
850 if (acnt >= MAX_FAILS_A)
857 acnt = 0; /* reset error counter for accept() */
859 dupfd = fcntl(connfd, F_DUPFD, 256);
860 if (ValidSocket(dupfd)
862 && SM_FD_OK_SELECT(dupfd)
863 # endif /* !SM_CONF_POLL */
868 dupfd = INVALID_SOCKET;
870 #endif /* _FFR_DUP_FD */
872 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
873 (void *) &sockopt, sizeof sockopt) < 0)
875 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)",
876 smfi->xxfi_name, sm_errstring(errno));
879 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
881 (void) closesocket(connfd);
883 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
884 smfi->xxfi_name, sm_errstring(save_errno),
885 mcnt >= MAX_FAILS_M ? "abort" : "try again");
887 if (mcnt >= MAX_FAILS_M)
894 mcnt = 0; /* reset error counter for malloc() */
895 (void) memset(ctx, '\0', sizeof *ctx);
896 ctx->ctx_sd = connfd;
898 ctx->ctx_timeout = timeout;
899 ctx->ctx_smfi = smfi;
901 if (smfi->xxfi_eoh == NULL)
902 if (smfi->xxfi_eom == NULL)
903 if (smfi->xxfi_abort == NULL)
904 if (smfi->xxfi_close == NULL)
906 if (smfi->xxfi_connect == NULL)
907 ctx->ctx_pflags |= SMFIP_NOCONNECT;
908 if (smfi->xxfi_helo == NULL)
909 ctx->ctx_pflags |= SMFIP_NOHELO;
910 if (smfi->xxfi_envfrom == NULL)
911 ctx->ctx_pflags |= SMFIP_NOMAIL;
912 if (smfi->xxfi_envrcpt == NULL)
913 ctx->ctx_pflags |= SMFIP_NORCPT;
914 if (smfi->xxfi_header == NULL)
915 ctx->ctx_pflags |= SMFIP_NOHDRS;
916 if (smfi->xxfi_eoh == NULL)
917 ctx->ctx_pflags |= SMFIP_NOEOH;
918 if (smfi->xxfi_body == NULL)
919 ctx->ctx_pflags |= SMFIP_NOBODY;
921 if ((r = thread_create(&thread_id,
922 mi_thread_handle_wrapper,
927 "%s: thread_create() failed: %d, %s",
929 tcnt >= MAX_FAILS_T ? "abort" : "try again");
931 (void) closesocket(connfd);
933 if (tcnt >= MAX_FAILS_T)
942 if (ret != MI_SUCCESS)
943 mi_stop_milters(MILTER_ABRT);
946 if (mistop != MILTER_CONT)
947 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
948 smfi->xxfi_name, mistop);
951 (void) smutex_destroy(&L_Mutex);