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
);