This is a patch to the libmilter library that ships with sendmail 8.12.11 to do the following: - Make the connection handling in listener.c extensible. - Support for DCE threads in HP-UX 10.20 (hasn't been tested in a couple of years, may be broken). Note that the changes preserve binary compatibility of the libmilter API. Apply using GNU patch like so: cd sendmail-8.12.11 patch -p1 -N < this_file Gurusamy Sarathy gsar@ActiveState.com --- sendmail-8.12.11/include/libmilter/mfapi.h 2003-10-20 14:51:49.000000000 -0700 +++ sendmail-8.12.11+/include/libmilter/mfapi.h 2004-03-04 11:54:33.000000000 -0800 @@ -37,6 +37,10 @@ #define MI_SUCCESS 0 #define MI_FAILURE (-1) +#define MI_HOOK_OK 0 +#define MI_HOOK_BREAK 1 +#define MI_HOOK_CONTINUE 2 + /* "forward" declarations */ typedef struct smfi_str SMFICTX; typedef struct smfi_str *SMFICTX_PTR; @@ -105,6 +109,18 @@ /* connection cleanup */ sfsistat (*xxfi_close) SM__P((SMFICTX *)); + + /* listener hooks */ + int (*xxmx_init) SM__P((smfiDesc_ptr)); + int (*xxmx_start) SM__P((smfiDesc_ptr, int *, int*, int*)); + int (*xxmx_accept) SM__P((smfiDesc_ptr, int, int*)); + int (*xxmx_timeout) SM__P((smfiDesc_ptr)); + int (*xxmx_dispatch) SM__P((smfiDesc_ptr, void*, void *(*) SM__P((void *)), void *, int, int)); + int (*xxmx_end) SM__P((smfiDesc_ptr)); + int (*xxmx_destroy) SM__P((smfiDesc_ptr)); + + /* engine hooks */ + int (*xxmx_run_engine) SM__P((SMFICTX *)); }; #if _FFR_SMFI_OPENSOCKET --- sendmail-8.12.11/include/libmilter/milter.h 2003-12-01 16:19:51.000000000 -0800 +++ sendmail-8.12.11+/include/libmilter/milter.h 2004-03-04 11:54:33.000000000 -0800 @@ -56,4 +56,14 @@ void *ctx_privdata; /* private data */ }; +#if defined(__hpux) && defined(__ux_version) && __ux_version <= 1020 +# define c2i(id) ((int)&(id)) +# define thread_detach(x) pthread_detach(&(x)) +# define pthread_sigmask(h,s,o) sigprocmask(h,s,o) +# define pthread_attr_init(a) pthread_attr_create(a) +#else +# define c2i(id) ((int)(id)) +# define thread_detach(x) pthread_detach(x) +# define pthread_mutexattr_default NULL +#endif #endif /* ! _LIBMILTER_MILTER_H */ --- sendmail-8.12.11/include/sm/string.h 2001-06-17 14:31:11.000000000 -0700 +++ sendmail-8.12.11+/include/sm/string.h 2004-03-04 11:54:34.000000000 -0800 @@ -23,12 +23,14 @@ /* return number of bytes left in a buffer */ #define SPACELEFT(buf, ptr) (sizeof buf - ((ptr) - buf)) +#if !defined(sm_snprintf) extern int PRINTFLIKE(3, 4) sm_snprintf __P(( char *, size_t, const char *, ...)); +#endif extern bool sm_match __P(( --- sendmail-8.12.11/libmilter/comm.c 2003-01-03 14:14:40.000000000 -0800 +++ sendmail-8.12.11+/libmilter/comm.c 2004-03-04 11:54:34.000000000 -0800 @@ -46,6 +46,16 @@ int save_errno; char *buf; char data[MILTER_LEN_BYTES + 1]; + struct timeval chktime; + struct timeval *pchktime; + + if (timeout) { + chktime = *timeout; + pchktime = &chktime; + } + else { + pchktime = NULL; + } *cmd = '\0'; *rlen = 0; @@ -53,8 +63,13 @@ i = 0; for (;;) { + /* some implementations of select() modify the timeout, + * so we need to reinitialize it */ + if (timeout) + chktime = *timeout; + FD_RD_INIT(sd, rds, excs); - ret = FD_RD_READY(sd, rds, excs, timeout); + ret = FD_RD_READY(sd, rds, excs, pchktime); if (ret == 0) break; else if (ret < 0) @@ -126,8 +141,11 @@ i = 0; for (;;) { + if (timeout) + chktime = *timeout; + FD_RD_INIT(sd, rds, excs); - ret = FD_RD_READY(sd, rds, excs, timeout); + ret = FD_RD_READY(sd, rds, excs, pchktime); if (ret == 0) break; else if (ret < 0) @@ -200,7 +218,7 @@ ** ** Parameters: ** sd -- socket descriptor -** timeout -- maximum time to wait (currently unused) +** timeout -- maximum time to wait ** cmd -- single character command to write ** buf -- buffer with further data ** len -- length of buffer (without cmd!) @@ -218,8 +236,10 @@ #define MI_WR(data) \ while (sl > 0) \ { \ - FD_WR_INIT(sd, wrs); \ - ret = FD_WR_READY(sd, wrs, timeout); \ + FD_WR_INIT(sd, rds, wrs); \ + ret = FD_WR_READY(sd, rds, wrs, pchktime); \ + if (timeout) \ + chktime = *timeout; \ if (ret == 0) \ return MI_FAILURE; \ if (ret < 0) \ @@ -229,6 +249,11 @@ else \ return MI_FAILURE; \ } \ + if (FD_IS_WR_HUP(sd, rds, wrs)) { \ + smi_log(SMI_LOG_ERR, \ + "EOF when trying to write cmd"); \ + return MI_FAILURE; \ + } \ l = MI_SOCK_WRITE(sd, (void *) ((data) + i), sl); \ if (l < 0) \ { \ @@ -253,8 +278,18 @@ ssize_t l; mi_int32 nl; int ret; - FD_WR_VAR(wrs); + FD_WR_VAR(rds, wrs); char data[MILTER_LEN_BYTES + 1]; + struct timeval chktime; + struct timeval *pchktime; + /* smi_log(SMI_LOG_DEBUG, "mi_wr_cmd '%c'\n", cmd); */ + if (timeout) { + chktime = *timeout; + pchktime = &chktime; + } + else { + pchktime = NULL; + } if (len > MILTER_CHUNK_SIZE) return MI_FAILURE; --- sendmail-8.12.11/libmilter/engine.c 2003-12-01 15:57:45.000000000 -0800 +++ sendmail-8.12.11+/libmilter/engine.c 2004-03-04 11:54:34.000000000 -0800 @@ -231,7 +231,7 @@ { if (ctx->ctx_dbg > 3) sm_dprintf("[%d] milter_abort\n", - (int) ctx->ctx_id); + c2i(ctx->ctx_id)); ret = MI_FAILURE; break; } @@ -253,7 +253,7 @@ { if (ctx->ctx_dbg > 5) sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n", - (int) ctx->ctx_id, (int) cmd); + c2i(ctx->ctx_id), (int) cmd); /* ** eof is currently treated as failure -> @@ -266,7 +266,7 @@ } if (ctx->ctx_dbg > 4) sm_dprintf("[%d] got cmd '%c' len %d\n", - (int) ctx->ctx_id, cmd, (int) len); + c2i(ctx->ctx_id), cmd, (int) len); for (i = 0; i < ncmds; i++) { if (cmd == cmds[i].cm_cmd) @@ -277,7 +277,7 @@ /* unknown command */ if (ctx->ctx_dbg > 1) sm_dprintf("[%d] cmd '%c' unknown\n", - (int) ctx->ctx_id, cmd); + c2i(ctx->ctx_id), cmd); ret = MI_FAILURE; break; } @@ -286,7 +286,7 @@ /* stop for now */ if (ctx->ctx_dbg > 1) sm_dprintf("[%d] cmd '%c' not impl\n", - (int) ctx->ctx_id, cmd); + c2i(ctx->ctx_id), cmd); ret = MI_FAILURE; break; } @@ -295,14 +295,14 @@ newstate = cmds[i].cm_next; if (ctx->ctx_dbg > 5) sm_dprintf("[%d] cur %x new %x nextmask %x\n", - (int) ctx->ctx_id, + c2i(ctx->ctx_id), curstate, newstate, next_states[curstate]); if (newstate != ST_NONE && !trans_ok(curstate, newstate)) { if (ctx->ctx_dbg > 1) sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n", - (int) ctx->ctx_id, + c2i(ctx->ctx_id), curstate, MI_MASK(curstate), newstate, MI_MASK(newstate), next_states[curstate]); @@ -370,7 +370,7 @@ { if (ctx->ctx_dbg > 5) sm_dprintf("[%d] function returned abort\n", - (int) ctx->ctx_id); + c2i(ctx->ctx_id)); ret = MI_FAILURE; break; } @@ -522,7 +522,7 @@ smi_log(SMI_LOG_ERR, "%s: st_optionneg[%d]: len too short %d < %d", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, (int) g->a_len, + c2i(g->a_ctx->ctx_id), (int) g->a_len, MILTER_OPTLEN); return _SMFIS_ABORT; } @@ -536,7 +536,7 @@ smi_log(SMI_LOG_ERR, "%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, (int) v, + c2i(g->a_ctx->ctx_id), (int) v, g->a_ctx->ctx_smfi->xxfi_version); return _SMFIS_ABORT; } @@ -554,7 +554,7 @@ smi_log(SMI_LOG_ERR, "%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, v, i); + c2i(g->a_ctx->ctx_id), v, i); return _SMFIS_ABORT; } @@ -571,7 +571,7 @@ smi_log(SMI_LOG_ERR, "%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, v, i); + c2i(g->a_ctx->ctx_id), v, i); return _SMFIS_ABORT; } @@ -624,7 +624,7 @@ smi_log(SMI_LOG_ERR, "%s: connect[%d]: wrong len %d >= %d", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, (int) i, (int) l); + c2i(g->a_ctx->ctx_id), (int) i, (int) l); return _SMFIS_ABORT; } (void) memcpy((void *) &port, (void *) (s + i), @@ -637,13 +637,12 @@ # if NETINET if (family == SMFIA_INET) { - if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) - != 1) + if (!inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr)) { smi_log(SMI_LOG_ERR, "%s: connect[%d]: inet_aton failed", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id); + c2i(g->a_ctx->ctx_id)); return _SMFIS_ABORT; } sockaddr.sa.sa_family = AF_INET; @@ -661,7 +660,7 @@ smi_log(SMI_LOG_ERR, "%s: connect[%d]: mi_inet_pton failed", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id); + c2i(g->a_ctx->ctx_id)); return _SMFIS_ABORT; } sockaddr.sa.sa_family = AF_INET6; @@ -680,7 +679,7 @@ smi_log(SMI_LOG_ERR, "%s: connect[%d]: path too long", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id); + c2i(g->a_ctx->ctx_id)); return _SMFIS_ABORT; } sockaddr.sunix.sun_family = AF_UNIX; @@ -691,7 +690,7 @@ smi_log(SMI_LOG_ERR, "%s: connect[%d]: unknown family %d", g->a_ctx->ctx_smfi->xxfi_name, - (int) g->a_ctx->ctx_id, family); + c2i(g->a_ctx->ctx_id), family); return _SMFIS_ABORT; } } --- sendmail-8.12.11/libmilter/handler.c 2003-01-23 14:28:36.000000000 -0800 +++ sendmail-8.12.11+/libmilter/handler.c 2004-03-04 11:54:34.000000000 -0800 @@ -32,6 +32,11 @@ if (ctx == NULL) return MI_FAILURE; + + if (ctx->ctx_smfi->xxmx_run_engine) { + ret = ctx->ctx_smfi->xxmx_run_engine(ctx); + } + else { ctx->ctx_id = (sthread_t) sthread_get_id(); /* @@ -43,6 +48,7 @@ ret = MI_FAILURE; else ret = mi_engine(ctx); + } if (ValidSocket(ctx->ctx_sd)) { (void) closesocket(ctx->ctx_sd); --- sendmail-8.12.11/libmilter/libmilter.h 2003-10-20 14:51:50.000000000 -0700 +++ sendmail-8.12.11+/libmilter/libmilter.h 2004-03-04 11:54:34.000000000 -0800 @@ -43,7 +43,7 @@ # define sthread_get_id() pthread_self() typedef pthread_mutex_t smutex_t; -# define smutex_init(mp) (pthread_mutex_init(mp, NULL) == 0) +# define smutex_init(mp) (pthread_mutex_init(mp, pthread_mutexattr_default) == 0) # define smutex_destroy(mp) (pthread_mutex_destroy(mp) == 0) # define smutex_lock(mp) (pthread_mutex_lock(mp) == 0) # define smutex_unlock(mp) (pthread_mutex_unlock(mp) == 0) @@ -59,28 +59,31 @@ # define MI_MS(timeout) (((timeout)->tv_sec * 1000) + (timeout)->tv_usec) # define FD_RD_VAR(rds, excs) struct pollfd rds -# define FD_WR_VAR(wrs) struct pollfd wrs +# define FD_WR_VAR(rds, wrs) struct pollfd wrs # define FD_RD_INIT(sd, rds, excs) \ (rds).fd = (sd); \ (rds).events = MI_POLL_RD_FLAGS; \ (rds).revents = 0 -# define FD_WR_INIT(sd, wrs) \ +# define FD_WR_INIT(sd, rds, wrs) \ (wrs).fd = (sd); \ - (wrs).events = MI_POLL_WR_FLAGS; \ + (wrs).events = MI_POLL_RD_FLAGS|MI_POLL_WR_FLAGS; \ (wrs).revents = 0 # define FD_IS_RD_EXC(sd, rds, excs) \ (((rds).revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) -# define FD_IS_WR_RDY(sd, wrs) \ +# define FD_IS_WR_HUP(sd, rds, wrs) \ + (((wrs).revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) != 0) + +# define FD_IS_WR_RDY(sd, rds, wrs) \ (((wrs).revents & MI_POLL_WR_FLAGS) != 0) # define FD_IS_RD_RDY(sd, rds, excs) \ (((rds).revents & MI_POLL_RD_FLAGS) != 0) -# define FD_WR_READY(sd, excs, timeout) \ +# define FD_WR_READY(sd, rds, excs, timeout) \ poll(&(wrs), 1, MI_MS(timeout)) # define FD_RD_READY(sd, rds, excs, timeout) \ @@ -92,7 +95,7 @@ # define MI_POLLSELECT "select" # define FD_RD_VAR(rds, excs) fd_set rds, excs -# define FD_WR_VAR(wrs) fd_set wrs +# define FD_WR_VAR(rds, wrs) fd_set rds, wrs # define FD_RD_INIT(sd, rds, excs) \ FD_ZERO(&(rds)); \ @@ -100,16 +103,19 @@ FD_ZERO(&(excs)); \ FD_SET((unsigned int) (sd), &(excs)) -# define FD_WR_INIT(sd, wrs) \ +# define FD_WR_INIT(sd, rds, wrs) \ + FD_ZERO(&(rds)); \ + FD_SET((unsigned int) (sd), &(rds)); \ FD_ZERO(&(wrs)); \ FD_SET((unsigned int) (sd), &(wrs)); \ # define FD_IS_RD_EXC(sd, rds, excs) FD_ISSET(sd, &(excs)) -# define FD_IS_WR_RDY(sd, wrs) FD_ISSET((sd), &(wrs)) +# define FD_IS_WR_HUP(sd, rds, wrs) FD_ISSET((sd), &(rds)) +# define FD_IS_WR_RDY(sd, rds, wrs) FD_ISSET((sd), &(wrs)) # define FD_IS_RD_RDY(sd, rds, excs) FD_ISSET((sd), &(rds)) -# define FD_WR_READY(sd, wrs, timeout) \ - select((sd) + 1, NULL, &(wrs), NULL, (timeout)) +# define FD_WR_READY(sd, rds, wrs, timeout) \ + select((sd) + 1, &(rds), &(wrs), NULL, (timeout)) # define FD_RD_READY(sd, rds, excs, timeout) \ select((sd) + 1, &(rds), NULL, &(excs), (timeout)) @@ -177,6 +183,7 @@ extern int mi_inet_pton __P((int, const char *, void *)); extern void mi_closener __P((void)); extern int mi_opensocket __P((char *, int, int, bool, smfiDesc_ptr)); +extern int mi_parse_sockspec __P((char *, SOCKADDR *, char *)); /* communication functions */ extern char *mi_rd_cmd __P((socket_t, struct timeval *, char *, size_t *, char *)); --- sendmail-8.12.11/libmilter/listener.c 2003-10-21 10:22:57.000000000 -0700 +++ sendmail-8.12.11+/libmilter/listener.c 2004-03-04 11:54:34.000000000 -0800 @@ -91,42 +91,13 @@ return MI_SUCCESS; } -/* -** MI_MILTEROPEN -- setup socket to listen on -** -** Parameters: -** conn -- connection description -** backlog -- listen backlog -** rmsocket -- if true, try to unlink() the socket first -** (UNIX domain sockets only) -** name -- name for logging -** -** Returns: -** socket upon success, error code otherwise. -** -** Side effect: -** sets sockpath if UNIX socket. -*/ - -#if NETUNIX -static char *sockpath = NULL; -#endif /* NETUNIX */ - -static socket_t -mi_milteropen(conn, backlog, rmsocket, name) - char *conn; - int backlog; - bool rmsocket; - char *name; +int +mi_parse_sockspec(char *conn, SOCKADDR *addr, char *name) { - socket_t sock; - int sockopt = 1; - int fdflags; size_t len = 0; char *p; char *colon; char *at; - SOCKADDR addr; if (conn == NULL || conn[0] == '\0') { @@ -134,7 +105,7 @@ name); return INVALID_SOCKET; } - (void) memset(&addr, '\0', sizeof addr); + (void) memset(addr, '\0', sizeof *addr); /* protocol:filename or protocol:port@host */ p = conn; @@ -147,18 +118,15 @@ { #if NETUNIX /* default to AF_UNIX */ - addr.sa.sa_family = AF_UNIX; - L_socksize = sizeof (struct sockaddr_un); + addr->sa.sa_family = AF_UNIX; #else /* NETUNIX */ # if NETINET /* default to AF_INET */ - addr.sa.sa_family = AF_INET; - L_socksize = sizeof addr.sin; + addr->sa.sa_family = AF_INET; # else /* NETINET */ # if NETINET6 /* default to AF_INET6 */ - addr.sa.sa_family = AF_INET6; - L_socksize = sizeof addr.sin6; + addr->sa.sa_family = AF_INET6; # else /* NETINET6 */ /* no protocols available */ smi_log(SMI_LOG_ERR, @@ -173,22 +141,19 @@ else if (strcasecmp(p, "unix") == 0 || strcasecmp(p, "local") == 0) { - addr.sa.sa_family = AF_UNIX; - L_socksize = sizeof (struct sockaddr_un); + addr->sa.sa_family = AF_UNIX; } #endif /* NETUNIX */ #if NETINET else if (strcasecmp(p, "inet") == 0) { - addr.sa.sa_family = AF_INET; - L_socksize = sizeof addr.sin; + addr->sa.sa_family = AF_INET; } #endif /* NETINET */ #if NETINET6 else if (strcasecmp(p, "inet6") == 0) { - addr.sa.sa_family = AF_INET6; - L_socksize = sizeof addr.sin6; + addr->sa.sa_family = AF_INET6; } #endif /* NETINET6 */ else @@ -204,18 +169,15 @@ colon = p; #if NETUNIX /* default to AF_UNIX */ - addr.sa.sa_family = AF_UNIX; - L_socksize = sizeof (struct sockaddr_un); + addr->sa.sa_family = AF_UNIX; #else /* NETUNIX */ # if NETINET /* default to AF_INET */ - addr.sa.sa_family = AF_INET; - L_socksize = sizeof addr.sin; + addr->sa.sa_family = AF_INET; # else /* NETINET */ # if NETINET6 /* default to AF_INET6 */ - addr.sa.sa_family = AF_INET6; - L_socksize = sizeof addr.sin6; + addr->sa.sa_family = AF_INET6; # else /* NETINET6 */ smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", name, p); @@ -226,7 +188,7 @@ } #if NETUNIX - if (addr.sa.sa_family == AF_UNIX) + if (addr->sa.sa_family == AF_UNIX) { # if 0 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; @@ -234,15 +196,15 @@ at = colon; len = strlen(colon) + 1; - if (len >= sizeof addr.sunix.sun_path) + if (len >= sizeof addr->sunix.sun_path) { errno = EINVAL; smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", name, colon); return INVALID_SOCKET; } - (void) sm_strlcpy(addr.sunix.sun_path, colon, - sizeof addr.sunix.sun_path); + (void) sm_strlcpy(addr->sunix.sun_path, colon, + sizeof addr->sunix.sun_path); # if 0 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, S_IRUSR|S_IWUSR, NULL); @@ -262,13 +224,13 @@ #if NETINET || NETINET6 if ( # if NETINET - addr.sa.sa_family == AF_INET + addr->sa.sa_family == AF_INET # endif /* NETINET */ # if NETINET && NETINET6 || # endif /* NETINET && NETINET6 */ # if NETINET6 - addr.sa.sa_family == AF_INET6 + addr->sa.sa_family == AF_INET6 # endif /* NETINET6 */ ) { @@ -278,17 +240,17 @@ at = strchr(colon, '@'); if (at == NULL) { - switch (addr.sa.sa_family) + switch (addr->sa.sa_family) { # if NETINET case AF_INET: - addr.sin.sin_addr.s_addr = INADDR_ANY; + addr->sin.sin_addr.s_addr = INADDR_ANY; break; # endif /* NETINET */ # if NETINET6 case AF_INET6: - addr.sin6.sin6_addr = in6addr_any; + addr->sin6.sin6_addr = in6addr_any; break; # endif /* NETINET6 */ } @@ -338,22 +300,22 @@ *end = '\0'; # if NETINET - if (addr.sa.sa_family == AF_INET && + if (addr->sa.sa_family == AF_INET && (hid = inet_addr(&at[1])) != INADDR_NONE) { - addr.sin.sin_addr.s_addr = hid; - addr.sin.sin_port = port; + addr->sin.sin_addr.s_addr = hid; + addr->sin.sin_port = port; found = true; } # endif /* NETINET */ # if NETINET6 (void) memset(&hid6, '\0', sizeof hid6); - if (addr.sa.sa_family == AF_INET6 && + if (addr->sa.sa_family == AF_INET6 && mi_inet_pton(AF_INET6, &at[1], &hid6.sin6_addr) == 1) { - addr.sin6.sin6_addr = hid6.sin6_addr; - addr.sin6.sin6_port = port; + addr->sin6.sin6_addr = hid6.sin6_addr; + addr->sin6.sin6_port = port; found = true; } # endif /* NETINET6 */ @@ -378,7 +340,7 @@ { struct hostent *hp = NULL; - hp = mi_gethostbyname(at, addr.sa.sa_family); + hp = mi_gethostbyname(at, addr->sa.sa_family); if (hp == NULL) { smi_log(SMI_LOG_ERR, @@ -386,24 +348,24 @@ name, at); return INVALID_SOCKET; } - addr.sa.sa_family = hp->h_addrtype; + addr->sa.sa_family = hp->h_addrtype; switch (hp->h_addrtype) { # if NETINET case AF_INET: - (void) memmove(&addr.sin.sin_addr, + (void) memmove(&addr->sin.sin_addr, hp->h_addr, INADDRSZ); - addr.sin.sin_port = port; + addr->sin.sin_port = port; break; # endif /* NETINET */ # if NETINET6 case AF_INET6: - (void) memmove(&addr.sin6.sin6_addr, + (void) memmove(&addr->sin6.sin6_addr, hp->h_addr, IN6ADDRSZ); - addr.sin6.sin6_port = port; + addr->sin6.sin6_port = port; break; # endif /* NETINET6 */ @@ -420,22 +382,75 @@ } else { - switch (addr.sa.sa_family) + switch (addr->sa.sa_family) { # if NETINET case AF_INET: - addr.sin.sin_port = port; + addr->sin.sin_port = port; break; # endif /* NETINET */ # if NETINET6 case AF_INET6: - addr.sin6.sin6_port = port; + addr->sin6.sin6_port = port; break; # endif /* NETINET6 */ } } } #endif /* NETINET || NETINET6 */ + return 0; +} + +/* +** MI_MILTEROPEN -- setup socket to listen on +** +** Parameters: +** conn -- connection description +** backlog -- listen backlog +** rmsocket -- if true, try to unlink() the socket first +** (UNIX domain sockets only) +** name -- name for logging +** +** Returns: +** socket upon success, error code otherwise. +** +** Side effect: +** sets sockpath if UNIX socket. +*/ + +#if NETUNIX +static char *sockpath = NULL; +#endif /* NETUNIX */ + +static socket_t +mi_milteropen(conn, backlog, rmsocket, name) + char *conn; + int backlog; + bool rmsocket; + char *name; +{ + socket_t sock; + int sockopt = 1; + int fdflags; + size_t len = 0; + SOCKADDR addr; + SOCKADDR_LEN_T addrlen = 0; + + if (mi_parse_sockspec(conn, &addr, name) != 0) + return INVALID_SOCKET; + +#if NETUNIX + if (addr.sa.sa_family == AF_UNIX) + addrlen = sizeof (struct sockaddr_un); +#endif /* NETUNIX */ +#if NETINET + if (addr.sa.sa_family == AF_INET) + addrlen = sizeof addr.sin; +#endif /* NETINET */ +#if NETINET6 + if (addr.sa.sa_family == AF_INET6) + addrlen = sizeof addr.sin6; +#endif /* NETINET6 */ sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); if (!ValidSocket(sock)) @@ -469,6 +484,7 @@ #if NETUNIX if (addr.sa.sa_family == AF_UNIX && rmsocket) { + char *colon = addr.sunix.sun_path; struct stat s; if (stat(colon, &s) != 0) @@ -501,7 +517,7 @@ } #endif /* NETUNIX */ - if (bind(sock, &addr.sa, L_socksize) < 0) + if (bind(sock, &addr.sa, addrlen) < 0) { smi_log(SMI_LOG_ERR, "%s: Unable to bind to port %s: %s", @@ -520,7 +536,8 @@ } #if NETUNIX - if (addr.sa.sa_family == AF_UNIX && len > 0) + if (addr.sa.sa_family == AF_UNIX + && (len = strlen(addr.sunix.sun_path)) > 0) { /* ** Set global variable sockpath so the UNIX socket can be @@ -529,7 +546,7 @@ sockpath = (char *) malloc(len); if (sockpath != NULL) - (void) sm_strlcpy(sockpath, colon, len); + (void) sm_strlcpy(sockpath, addr.sunix.sun_path, len); else { smi_log(SMI_LOG_ERR, @@ -540,6 +557,7 @@ } } #endif /* NETUNIX */ + L_socksize = addrlen; L_family = addr.sa.sa_family; return sock; } @@ -718,41 +736,67 @@ SMFICTX_PTR ctx; FD_RD_VAR(rds, excs); struct timeval chktime; + int nlistenfd; if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE) return MI_FAILURE; + if (smfi->xxmx_init + && smfi->xxmx_init(smfi) != MI_HOOK_OK) + { + (void) smutex_unlock(&L_Mutex); + return MI_FAILURE; + } + + nlistenfd = listenfd; clilen = L_socksize; (void) smutex_unlock(&L_Mutex); while ((mistop = mi_stop()) == MILTER_CONT) { (void) smutex_lock(&L_Mutex); - if (!ValidSocket(listenfd)) + if (!ValidSocket(nlistenfd)) { ret = MI_FAILURE; smi_log(SMI_LOG_ERR, "%s: listenfd=%d corrupted, terminating, errno=%d", - smfi->xxfi_name, listenfd, errno); + smfi->xxfi_name, nlistenfd, errno); (void) smutex_unlock(&L_Mutex); break; } + if (smfi->xxmx_start) { + int r = smfi->xxmx_start(smfi, &listenfd, &nlistenfd, &ret); + if (r == MI_HOOK_BREAK) { + (void) smutex_unlock(&L_Mutex); + break; + } + else if (r == MI_HOOK_CONTINUE) { + (void) smutex_unlock(&L_Mutex); + continue; + } + } + /* select on interface ports */ - FD_RD_INIT(listenfd, rds, excs); + FD_RD_INIT(nlistenfd, rds, excs); chktime.tv_sec = MI_CHK_TIME; chktime.tv_usec = 0; - r = FD_RD_READY(listenfd, rds, excs, &chktime); + do { + r = FD_RD_READY(nlistenfd, rds, excs, &chktime); + } while (r < 0 && errno == EINTR); if (r == 0) /* timeout */ { (void) smutex_unlock(&L_Mutex); + if (smfi->xxmx_timeout) { + int r = smfi->xxmx_timeout(smfi); + if (r == MI_HOOK_BREAK) + break; + } continue; /* just check mi_stop() */ } if (r < 0) { save_errno = errno; (void) smutex_unlock(&L_Mutex); - if (save_errno == EINTR) - continue; scnt++; smi_log(SMI_LOG_ERR, "%s: select() failed (%s), %s", @@ -766,7 +810,7 @@ } continue; } - if (!FD_IS_RD_RDY(listenfd, rds, excs)) + if (!FD_IS_RD_RDY(nlistenfd, rds, excs)) { /* some error: just stop for now... */ ret = MI_FAILURE; @@ -778,8 +822,17 @@ } scnt = 0; /* reset error counter for select() */ + if (smfi->xxmx_accept) { + int r = smfi->xxmx_accept(smfi, nlistenfd, &connfd); + (void) smutex_unlock(&L_Mutex); + if (r == MI_HOOK_BREAK) + break; + else if (r == MI_HOOK_CONTINUE) + continue; + } + else { (void) memset(&cliaddr, '\0', sizeof cliaddr); - connfd = accept(listenfd, (struct sockaddr *) &cliaddr, + connfd = accept(nlistenfd, (struct sockaddr *) &cliaddr, &clilen); save_errno = errno; (void) smutex_unlock(&L_Mutex); @@ -830,6 +883,7 @@ continue; } acnt = 0; /* reset error counter for accept() */ + } if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, (void *) &sockopt, sizeof sockopt) < 0) @@ -880,9 +934,13 @@ if (smfi->xxfi_body == NULL) ctx->ctx_pflags |= SMFIP_NOBODY; - if ((r = thread_create(&thread_id, + if ((r = (smfi->xxmx_dispatch + ? smfi->xxmx_dispatch(smfi, &thread_id, + mi_thread_handle_wrapper, + (void *) ctx, nlistenfd, connfd) + : thread_create(&thread_id, mi_thread_handle_wrapper, - (void *) ctx)) != 0) + (void *) ctx))) != 0) { tcnt++; smi_log(SMI_LOG_ERR, @@ -891,7 +949,8 @@ tcnt >= MAX_FAILS_T ? "abort" : "try again"); MI_SLEEP(tcnt); (void) closesocket(connfd); - free(ctx); + if (!smfi->xxmx_dispatch) + free(ctx); if (tcnt >= MAX_FAILS_T) { ret = MI_FAILURE; @@ -901,6 +960,8 @@ } tcnt = 0; } + if (smfi->xxmx_end) + smfi->xxmx_end(smfi); if (ret != MI_SUCCESS) mi_stop_milters(MILTER_ABRT); else @@ -911,5 +972,7 @@ mi_closener(); } (void) smutex_destroy(&L_Mutex); + if (smfi->xxmx_destroy) + smfi->xxmx_destroy(smfi); return ret; } --- sendmail-8.12.11/libmilter/signal.c 2003-11-18 16:22:40.000000000 -0800 +++ sendmail-8.12.11+/libmilter/signal.c 2004-03-04 11:54:34.000000000 -0800 @@ -101,7 +101,7 @@ for (;;) { sig = 0; -#if defined(SOLARIS) || defined(__svr5__) +#if (defined(SOLARIS) && !defined(_POSIX_PTHREAD_SEMANTICS)) || defined(__svr5__) || (defined(__hpux) && defined(__ux_version) && __ux_version <= 1020) if ((sig = sigwait(&set)) < 0) #else /* defined(SOLARIS) || defined(__svr5__) */ if (sigwait(&set, &sig) != 0) End of Patch.