aboutsummaryrefslogtreecommitdiffstats
path: root/mail/sendmail
diff options
context:
space:
mode:
authordinoex <dinoex@FreeBSD.org>2004-03-26 22:05:33 +0800
committerdinoex <dinoex@FreeBSD.org>2004-03-26 22:05:33 +0800
commit70d6020bf55876721c0c2a1c5e7bce8cd55b0d4f (patch)
treec20e5779b0d476a1bacb1daf19c46e0dbf89c4e3 /mail/sendmail
parent212ef0364720e0c757be48690d600f798830e1f9 (diff)
downloadfreebsd-ports-gnome-70d6020bf55876721c0c2a1c5e7bce8cd55b0d4f.tar.gz
freebsd-ports-gnome-70d6020bf55876721c0c2a1c5e7bce8cd55b0d4f.tar.zst
freebsd-ports-gnome-70d6020bf55876721c0c2a1c5e7bce8cd55b0d4f.zip
Add socket map support to the sendmail port (from 8.13.0)
This will allow for easier integration with e.g. ports/mail/cyrus-imapd22, which already includes smmapd for realtime checking whether the mailbox exists and is not over quota. The patch adds 1) an extra knob in Makefile (WITH_SENDMAIL_SOCKETMAP). 3) the extra-patch-socketmap.patch is actually http://www.sendmail.org/~ca/email/patches/sendmail-8.12.7-socketmap-v4.patch slightly hacked (the pathnames) so it cleanly applies through ports(7). PR: 64566 Submitted by: Michael O. Boev - change PKGNAMESUFFIX - merge 1-line site.config.m4.* files into Makefile - update CONFLICTS
Diffstat (limited to 'mail/sendmail')
-rw-r--r--mail/sendmail/Makefile69
-rw-r--r--mail/sendmail/files/site.config.m4.smtps1
-rw-r--r--mail/sendmail/files/socketmap.patch798
3 files changed, 855 insertions, 13 deletions
diff --git a/mail/sendmail/Makefile b/mail/sendmail/Makefile
index 5ca67264de40..7d6bf1b37ce7 100644
--- a/mail/sendmail/Makefile
+++ b/mail/sendmail/Makefile
@@ -10,13 +10,14 @@ PORTVERSION= 8.12.11
CATEGORIES= mail ipv6
MASTER_SITES= ftp://ftp.sendmail.org/pub/sendmail/ \
${MASTER_SITE_RINGSERVER:S,%SUBDIR%,net/mail/sendmail/&,}
+PKGNAMESUFFIX?= ${TLS_SUFFIX}${SASL_SUFFIX}${LDAP_SUFFIX}${PKGNAMESUFFIX2}
DISTNAME= ${PORTNAME}.${PORTVERSION}
MAINTAINER= dinoex@FreeBSD.org
COMMENT= Reliable, highly configurable mail transfer agent with utilities
-CONFLICTS?= courier-0.* postfix-1.* postfix-2.* sendmail-8.11.* sendmail-*-8.11.* \
- smail-3.* zmailer-2.*
+CONFLICTS?= courier-0.* postfix-1.* postfix-2.* smail-3.* zmailer-2.*
+CONFLICTS+= sendmail-8.11.* sendmail-*-8.11.* sendmail+*-8.11.*
WRKSRC= ${WRKDIR}/${PORTNAME}-${PORTVERSION}
WCONF= ${WRKSRC}/devtools/Site
@@ -43,6 +44,7 @@ PKGMESSAGE= ${WRKSRC}/pkg-message
# SENDMAIL_WITH_SASL=yes
# SENDMAIL_WITH_SASL2=yes
# SENDMAIL_WITH_LDAP=yes
+# SENDMAIL_WITH_SOCKETMAP=yes
# SENDMAIL_WITH_PICKY_HELO_CHECK=yes
.if defined(SENDMAIL_WITH_SMTPS)
@@ -54,25 +56,61 @@ pre-configure:
.endif
.if defined(SENDMAIL_WITH_LDAP)
-PKGNAMESUFFIX?= -ldap
+LDAP_SUFFIX?= +ldap
+CONFLICTS+= sendmail+tls-8.* \
+ sendmail+tls+sasl1-8.* \
+ sendmail+tls+sasl2-8.* \
+ sendmail+sasl1-8.* \
+ sendmail+sasl2-8.*
CONFLICTS+= sendmail-sasl-8.* sendmail-sasl2-8.* sendmail-tls-8.*
LIB_DEPENDS+= ldap.2:${PORTSDIR}/${LDAP_PORT}
LIB_DEPENDS+= lber.2:${PORTSDIR}/${LDAP_PORT}
+.else
+CONFLICTS+= sendmail*+ldap*-8.*
.endif
.if defined(SENDMAIL_WITH_SASL)
-LIB_DEPENDS+= sasl.8:${PORTSDIR}/security/cyrus-sasl
-PKGNAMESUFFIX?= -sasl
+SASL_SUFFIX?= +sasl1
+CONFLICTS+= sendmail+tls-8.* \
+ sendmail+tls+ldap-8.* \
+ sendmail+tls+sasl2-8.* \
+ sendmail+tls+sasl2+ldap-8.* \
+ sendmail+sasl2-8.* \
+ sendmail+sasl2+ldap-8.* \
+ sendmail+ldap-8.*
CONFLICTS+= sendmail-ldap-8.* sendmail-sasl2-8.* sendmail-tls-8.*
+LIB_DEPENDS+= sasl.8:${PORTSDIR}/security/cyrus-sasl
+.else
+CONFLICTS+= sendmail*+sasl1*-8.*
.endif
.if defined(SENDMAIL_WITH_SASL2)
+SASL_SUFFIX?= +sasl2
+CONFLICTS+= sendmail+tls-8.* \
+ sendmail+tls+ldap-8.* \
+ sendmail+tls+sasl-8.* \
+ sendmail+tls+sasl+ldap-8.* \
+ sendmail+sasl-8.* \
+ sendmail+sasl+ldap-8.* \
+ sendmail+ldap-8.*
+CONFLICTS+= sendmail-ldap-8.* sendmail-sasl-8.* sendmail-tls-8.*
+LIB_DEPENDS+= sasl.8:${PORTSDIR}/security/cyrus-sasl
LIB_DEPENDS+= sasl2.2:${PORTSDIR}/security/cyrus-sasl2
RUN_DEPENDS+= ${LOCALBASE}/sbin/saslauthd:${PORTSDIR}/security/cyrus-sasl2-saslauthd
-PKGNAMESUFFIX?= -sasl2
-CONFLICTS+= sendmail-ldap-8.* sendmail-sasl-8.* sendmail-tls-8.*
+.else
+CONFLICTS+= sendmail*+sasl2*-8.*
+.endif
+.if defined(SENDMAIL_WITH_SOCKETMAP)
+EXTRA_PATCHES+= ${FILESDIR}/socketmap.patch
.endif
.if defined(SENDMAIL_WITH_TLS) || defined(WITH_TLS)
-PKGNAMESUFFIX?= -tls
+TLS_SUFFIX?= +tls
+CONFLICTS+= sendmail+sasl-8.* \
+ sendmail+sasl+ldap-8.* \
+ sendmail+sasl2-8.* \
+ sendmail+sasl2+ldap-8.* \
+ sendmail+ldap-8.*
CONFLICTS+= sendmail-ldap-8.* sendmail-sasl-8.* sendmail-sasl2-8.*
+.else
+CONFLICTS+= sendmail*+tls*-8.*
.endif
# Build site.config.m4
@@ -126,9 +164,19 @@ do-configure:
${SED} -e "s=%%PREFIX%%=${PREFIX}=g" \
-e "s=%%LOCALBASE%%=${LOCALBASE}=g" \
${SITE} > ${WCONF}/site.config.m4
+.if defined(SENDMAIL_WITH_SMTPS)
+ ${ECHO_CMD} \
+ 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-D_FFR_SMTP_SSL'\'') \
+ >> ${WCONF}/site.config.m4
+.endif
+.if defined(SENDMAIL_WITH_SOCKETMAP)
+ ${ECHO_CMD} \
+ 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-DSOCKETMAP'\'')' \
+ >> ${WCONF}/site.config.m4
+.endif
.if defined(SENDMAIL_WITH_PICKY_HELO_CHECK)
${ECHO_CMD} \
- 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-DPICKY_HELO_CHECK'\'')' \
+ 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-DPICKY_HELO_CHECK'\'')' \
>> ${WCONF}/site.config.m4
.endif
.if defined(SENDMAIL_WITHOUT_SHMEM)
@@ -283,9 +331,6 @@ tls-install:
SITE+= ${FILESDIR}/site.config.m4.ssl
.endif
SITE+= ${FILESDIR}/site.config.m4.tls
-.if defined(SENDMAIL_WITH_SMTPS)
-SITE+= ${FILESDIR}/site.config.m4.smtps
-.endif
.endif
.if exists(${FILESDIR}/site.config.m4.local)
diff --git a/mail/sendmail/files/site.config.m4.smtps b/mail/sendmail/files/site.config.m4.smtps
deleted file mode 100644
index f66b5fa440cd..000000000000
--- a/mail/sendmail/files/site.config.m4.smtps
+++ /dev/null
@@ -1 +0,0 @@
-APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_SMTP_SSL')
diff --git a/mail/sendmail/files/socketmap.patch b/mail/sendmail/files/socketmap.patch
new file mode 100644
index 000000000000..ea128dbace71
--- /dev/null
+++ b/mail/sendmail/files/socketmap.patch
@@ -0,0 +1,798 @@
+Index: sendmail/sendmail/sendmail/README
+diff -u sendmail/sendmail/sendmail/README:1.1.1.2 sendmail/sendmail/sendmail/README:1.3
+--- sendmail/README Thu Jan 23 11:50:26 2003
++++ sendmail/README Tue Jan 28 16:55:41 2003
+@@ -127,6 +127,8 @@
+ PH_MAP PH map support. You will need the libphclient library from
+ the nph package (http://www-dev.cso.uiuc.edu/ph/nph/).
+ MAP_NSD nsd map support (IRIX 6.5 and later).
++SOCKETMAP Support for a trivial query protocol over UNIX domain or TCP
++ sockets.
+
+ >>> NOTE WELL for NEWDB support: If you want to get ndbm support, for
+ >>> Berkeley DB versions under 2.0, it is CRITICAL that you remove
+@@ -180,6 +182,50 @@
+ check_* rule-set, you can block a certain range of addresses that would
+ otherwise be considered valid.
+
++The socket map uses a simple request/reply protocol over TCP or UNIX domain
++sockets to query an external server. Both requests and replies are text
++based and encoded as D.J. Bernsteins netstrings. E.g., a string
++"hello there" becomes:
++11:hello there,
++
++NB. neither requests nor replies end with CRLF.
++
++The request consists of the database map name and the lookup key separated
++by a space character:
++
++<mapname> ' ' <key>
++
++The server responds with a status indicator and the result (if any):
++
++<status> ' ' <result> <LF>
++
++The status indicator is one of the following upper case words:
++OK (the key was found, result contains the looked up value)
++NOTFOUND (the key was not found, the result is empty)
++TEMP (a temporary failure occured)
++TIMEOUT (a timeout occured on the server side)
++PERM (a permanent failure occured)
++
++In case of errors (status TEMP, TIMEOUT or PERM) the result fied may
++contain an explanatory message.
++
++Example replies:
++30:OK resolved.addess@example.com,
++
++in case of a successful lookup, or:
++7:NOTFOUND,
++
++in case the key was not found, or:
++54:TEMP this text explains that we had a temporary failure,
++
++in case of a failure.
++
++The socket map uses the same syntax as milters the specify the remote
++endpoint. E.g.:
++Ksocket mySocketMap inet:12345@127.0.0.1
++
++If multiple socket maps define the same remote endpoint, they will share
++a single connection to this endpoint.
+
+ +---------------+
+ | COMPILE FLAGS |
+Index: sendmail/sendmail/sendmail/conf.c
+diff -u sendmail/sendmail/sendmail/conf.c:1.1.1.2 sendmail/sendmail/sendmail/conf.c:1.6
+--- sendmail/conf.c Thu Jan 23 11:50:27 2003
++++ sendmail/conf.c Fri Jan 24 15:31:59 2003
+@@ -622,6 +622,13 @@
+ dequote_init, null_map_open, null_map_close,
+ arith_map_lookup, null_map_store);
+
++#if SOCKETMAP
++ /* arbitrary daemons */
++ MAPDEF("socket", NULL, MCF_ALIASOK,
++ map_parseargs, socket_map_open, socket_map_close,
++ socket_map_lookup, null_map_store);
++#endif /* SOCKETMAP */
++
+ if (tTd(38, 2))
+ {
+ /* bogus map -- always return tempfail */
+Index: sendmail/sendmail/sendmail/map.c
+diff -u sendmail/sendmail/sendmail/map.c:1.1.1.2 sendmail/sendmail/sendmail/map.c:1.25
+--- sendmail/map.c Thu Jan 23 11:50:27 2003
++++ sendmail/map.c Tue Feb 25 14:57:14 2003
+@@ -66,6 +66,9 @@
+ static bool ni_getcanonname __P((char *, int, int *));
+ #endif /* NETINFO */
+ static bool text_getcanonname __P((char *, int, int *));
++#ifdef SOCKETMAP
++static STAB * socket_map_findconn __P((const char*));
++#endif /* SOCKETMAP */
+
+ /* default error message for trying to open a map in write mode */
+ #ifdef ENOSYS
+@@ -7395,3 +7398,646 @@
+ *statp = EX_CONFIG;
+ return NULL;
+ }
++
++#ifdef SOCKETMAP
++
++# if NETINET || NETINET6
++# include <arpa/inet.h>
++# endif /* NETINET || NETINET6 */
++
++#define socket_map_next map_stack[0]
++#define socket_map_previous map_stack[1]
++
++/*
++** SOCKET_MAP_OPEN -- open socket table
++*/
++
++bool
++socket_map_open(map, mode)
++ MAP *map;
++ int mode;
++{
++ STAB *s;
++
++ int sock = 0;
++ SOCKADDR_LEN_T addrlen = 0;
++ int addrno = 0;
++ int save_errno;
++ char *p;
++ char *colon;
++ char *at;
++ struct hostent *hp = NULL;
++ SOCKADDR addr;
++
++ if (tTd(38, 2))
++ sm_dprintf("socket_map_open(%s, %s, %d)\n",
++ map->map_mname, map->map_file, mode);
++
++ mode &= O_ACCMODE;
++
++ /* sendmail doesn't have the ability to write to SOCKET (yet) */
++ if (mode != O_RDONLY)
++ {
++ /* issue a pseudo-error message */
++ errno = SM_EMAPCANTWRITE;
++ return false;
++ }
++
++ if (*map->map_file == '\0')
++ {
++ syserr("socket map \"%s\": empty or missing socket information",
++ map->map_mname);
++ return false;
++ }
++
++ s = socket_map_findconn(map->map_file);
++ if (s->s_socketmap != NULL)
++ {
++ /* Copy open connection */
++ map->map_db1 = s->s_socketmap->map_db1;
++
++ /* Add this map as head of linked list */
++ map->socket_map_next = s->s_socketmap;
++ s->s_socketmap = map;
++
++ if (tTd(38, 2))
++ sm_dprintf("using cached connection\n");
++ return true;
++ }
++
++ if (tTd(38, 2))
++ sm_dprintf("opening new connection\n");
++
++
++
++ /* following code is ripped from milter.c */
++
++ /* protocol:filename or protocol:port@host */
++ memset(&addr, '\0', sizeof addr);
++ p = map->map_file;
++ colon = strchr(p, ':');
++ if (colon != NULL)
++ {
++ *colon = '\0';
++
++ if (*p == '\0')
++ {
++# if NETUNIX
++ /* default to AF_UNIX */
++ addr.sa.sa_family = AF_UNIX;
++# else /* NETUNIX */
++# if NETINET
++ /* default to AF_INET */
++ addr.sa.sa_family = AF_INET;
++# else /* NETINET */
++# if NETINET6
++ /* default to AF_INET6 */
++ addr.sa.sa_family = AF_INET6;
++# else /* NETINET6 */
++ /* no protocols available */
++ syserr("socket map \"%s\": no valid socket protocols available",
++ map->map_mname);
++ return false;
++# endif /* NETINET6 */
++# endif /* NETINET */
++# endif /* NETUNIX */
++ }
++# if NETUNIX
++ else if (sm_strcasecmp(p, "unix") == 0 ||
++ sm_strcasecmp(p, "local") == 0)
++ addr.sa.sa_family = AF_UNIX;
++# endif /* NETUNIX */
++# if NETINET
++ else if (sm_strcasecmp(p, "inet") == 0)
++ addr.sa.sa_family = AF_INET;
++# endif /* NETINET */
++# if NETINET6
++ else if (sm_strcasecmp(p, "inet6") == 0)
++ addr.sa.sa_family = AF_INET6;
++# endif /* NETINET6 */
++ else
++ {
++# ifdef EPROTONOSUPPORT
++ errno = EPROTONOSUPPORT;
++# else /* EPROTONOSUPPORT */
++ errno = EINVAL;
++# endif /* EPROTONOSUPPORT */
++ syserr("socket map \"%s\": unknown socket type %s",
++ map->map_mname, p);
++ return false;
++ }
++ *colon++ = ':';
++ }
++ else
++ {
++ /* default to AF_UNIX */
++ addr.sa.sa_family = AF_UNIX;
++ colon = p;
++ }
++
++# if NETUNIX
++ if (addr.sa.sa_family == AF_UNIX)
++ {
++ long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
++
++ at = colon;
++ if (strlen(colon) >= sizeof addr.sunix.sun_path)
++ {
++ syserr("socket map \"%s\": local socket name %s too long",
++ map->map_mname, colon);
++ return false;
++ }
++ errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
++ S_IRUSR|S_IWUSR, NULL);
++
++ if (errno != 0)
++ {
++ /* if not safe, don't create */
++ syserr("socket map \"%s\": local socket name %s unsafe",
++ map->map_mname, colon);
++ return false;
++ }
++
++ (void) sm_strlcpy(addr.sunix.sun_path, colon,
++ sizeof addr.sunix.sun_path);
++ addrlen = sizeof (struct sockaddr_un);
++ }
++ else
++# endif /* NETUNIX */
++# if NETINET || NETINET6
++ if (false
++# if NETINET
++ || addr.sa.sa_family == AF_INET
++# endif /* NETINET */
++# if NETINET6
++ || addr.sa.sa_family == AF_INET6
++# endif /* NETINET6 */
++ )
++ {
++ unsigned short port;
++
++ /* Parse port@host */
++ at = strchr(colon, '@');
++ if (at == NULL)
++ {
++ syserr("socket map \"%s\": bad address %s (expected port@host)",
++ map->map_mname, colon);
++ return false;
++ }
++ *at = '\0';
++ if (isascii(*colon) && isdigit(*colon))
++ port = htons((unsigned short) atoi(colon));
++ else
++ {
++# ifdef NO_GETSERVBYNAME
++ syserr("socket map \"%s\": invalid port number %s",
++ map->map_mname, colon);
++ return false;
++# else /* NO_GETSERVBYNAME */
++ register struct servent *sp;
++
++ sp = getservbyname(colon, "tcp");
++ if (sp == NULL)
++ {
++ syserr("socket map \"%s\": unknown port name %s",
++ map->map_mname, colon);
++ return false;
++ }
++ port = sp->s_port;
++# endif /* NO_GETSERVBYNAME */
++ }
++ *at++ = '@';
++ if (*at == '[')
++ {
++ char *end;
++
++ end = strchr(at, ']');
++ if (end != NULL)
++ {
++ bool found = false;
++# if NETINET
++ unsigned long hid = INADDR_NONE;
++# endif /* NETINET */
++# if NETINET6
++ struct sockaddr_in6 hid6;
++# endif /* NETINET6 */
++
++ *end = '\0';
++# if NETINET
++ 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;
++ found = true;
++ }
++# endif /* NETINET */
++# if NETINET6
++ (void) memset(&hid6, '\0', sizeof hid6);
++ if (addr.sa.sa_family == AF_INET6 &&
++ anynet_pton(AF_INET6, &at[1],
++ &hid6.sin6_addr) == 1)
++ {
++ addr.sin6.sin6_addr = hid6.sin6_addr;
++ addr.sin6.sin6_port = port;
++ found = true;
++ }
++# endif /* NETINET6 */
++ *end = ']';
++ if (!found)
++ {
++ syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
++ map->map_mname, at);
++ return false;
++ }
++ }
++ else
++ {
++ syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
++ map->map_mname, at);
++ return false;
++ }
++ }
++ else
++ {
++ hp = sm_gethostbyname(at, addr.sa.sa_family);
++ if (hp == NULL)
++ {
++ syserr("socket map \"%s\": Unknown host name %s",
++ map->map_mname, at);
++ return false;
++ }
++ addr.sa.sa_family = hp->h_addrtype;
++ switch (hp->h_addrtype)
++ {
++# if NETINET
++ case AF_INET:
++ memmove(&addr.sin.sin_addr,
++ hp->h_addr, INADDRSZ);
++ addr.sin.sin_port = port;
++ addrlen = sizeof (struct sockaddr_in);
++ addrno = 1;
++ break;
++# endif /* NETINET */
++
++# if NETINET6
++ case AF_INET6:
++ memmove(&addr.sin6.sin6_addr,
++ hp->h_addr, IN6ADDRSZ);
++ addr.sin6.sin6_port = port;
++ addrlen = sizeof (struct sockaddr_in6);
++ addrno = 1;
++ break;
++# endif /* NETINET6 */
++
++ default:
++ syserr("socket map \"%s\": Unknown protocol for %s (%d)",
++ map->map_mname, at, hp->h_addrtype);
++# if NETINET6
++ freehostent(hp);
++# endif /* NETINET6 */
++ return false;
++ }
++ }
++ }
++ else
++# endif /* NETINET || NETINET6 */
++ {
++ syserr("socket map \"%s\": unknown socket protocol", map->map_mname);
++ return false;
++ }
++
++ /* nope, actually connecting */
++ for (;;)
++ {
++ sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
++ if (sock < 0)
++ {
++ save_errno = errno;
++ if (tTd(38, 5))
++ sm_dprintf("socket map \"%s\": error creating socket: %s\n",
++ map->map_mname,
++ sm_errstring(save_errno));
++# if NETINET6
++ if (hp != NULL)
++ freehostent(hp);
++# endif /* NETINET6 */
++ return false;
++ }
++
++ if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
++ break;
++
++ /* couldn't connect.... try next address */
++ save_errno = errno;
++ p = CurHostName;
++ CurHostName = at;
++ if (tTd(38, 5))
++ sm_dprintf("socket_open (%s): open %s failed: %s\n",
++ map->map_mname, at, sm_errstring(save_errno));
++ CurHostName = p;
++ (void) close(sock);
++
++ /* try next address */
++ if (hp != NULL && hp->h_addr_list[addrno] != NULL)
++ {
++ switch (addr.sa.sa_family)
++ {
++# if NETINET
++ case AF_INET:
++ memmove(&addr.sin.sin_addr,
++ hp->h_addr_list[addrno++],
++ INADDRSZ);
++ break;
++# endif /* NETINET */
++
++# if NETINET6
++ case AF_INET6:
++ memmove(&addr.sin6.sin6_addr,
++ hp->h_addr_list[addrno++],
++ IN6ADDRSZ);
++ break;
++# endif /* NETINET6 */
++
++ default:
++ if (tTd(38, 5))
++ sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
++ map->map_mname, at,
++ hp->h_addrtype);
++# if NETINET6
++ freehostent(hp);
++# endif /* NETINET6 */
++ return false;
++ }
++ continue;
++ }
++ p = CurHostName;
++ CurHostName = at;
++ if (tTd(38, 5))
++ sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
++ map->map_mname, sm_errstring(save_errno));
++ CurHostName = p;
++# if NETINET6
++ if (hp != NULL)
++ freehostent(hp);
++# endif /* NETINET6 */
++ return false;
++ }
++# if NETINET6
++ if (hp != NULL)
++ {
++ freehostent(hp);
++ hp = NULL;
++ }
++# endif /* NETINET6 */
++ if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
++ SM_TIME_DEFAULT,
++ (void *) &sock,
++ SM_IO_RDWR,
++ NULL)) == NULL)
++ {
++ close(sock);
++ if (tTd(38, 2))
++ sm_dprintf("socket_open (%s): failed to create stream: %s\n",
++ map->map_mname, sm_errstring(errno));
++ return false;
++ }
++
++ /* Save connection for reuse */
++ s->s_socketmap = map;
++ return true;
++}
++
++/*
++** SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
++**
++** Cache SOCKET connections based on the connection specifier
++** and PID so we don't have multiple connections open to
++** the same server for different maps. Need a separate connection
++** per PID since a parent process may close the map before the
++** child is done with it.
++**
++** Parameters:
++** conn -- SOCKET map connection specifier
++**
++** Returns:
++** Symbol table entry for the SOCKET connection.
++*/
++
++static STAB *
++socket_map_findconn(conn)
++ const char *conn;
++{
++ char *format;
++ char *nbuf;
++ STAB *SM_NONVOLATILE s = NULL;
++
++ format = "%s%c%d";
++ nbuf = sm_stringf_x(format,
++ conn,
++ CONDELSE,
++ (int) CurrentPid);
++ if (tTd(38, 20))
++ sm_dprintf("socket_find_conn '%s'\n", nbuf);
++ SM_TRY
++ s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
++ SM_FINALLY
++ sm_free(nbuf);
++ SM_END_TRY
++ return s;
++}
++
++/*
++** SOCKET_MAP_CLOSE -- close the socket
++*/
++
++void
++socket_map_close(map)
++ MAP *map;
++{
++ STAB *s;
++ MAP *smap;
++
++ if (tTd(38, 20))
++ sm_dprintf("socket_map_close(%s), pid=%d\n", map->map_file,(int) CurrentPid);
++
++ /* Check if already closed */
++ if (!map->map_db1)
++ {
++ if (tTd(38, 20))
++ sm_dprintf("socket_map_close(%s) already closed\n", map->map_file);
++ return;
++ }
++
++ sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
++
++ /* Mark all the maps that share the connection as closed */
++ s = socket_map_findconn(map->map_file);
++
++ smap = s->s_socketmap;
++
++ while (smap != NULL)
++ {
++ MAP *next;
++
++ if (tTd(38, 2) && smap != map)
++ sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
++ map->map_mname, smap->map_mname);
++
++ smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
++ smap->map_db1 = NULL;
++ next = smap->socket_map_next;
++ smap->socket_map_next = NULL;
++ smap = next;
++ }
++
++ s->s_socketmap = NULL;
++}
++
++/*
++** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
++*/
++
++char *
++socket_map_lookup(map, name, av, statp)
++ MAP *map;
++ char *name;
++ char **av;
++ int *statp;
++{
++ size_t nettolen;
++ char *rval = NULL;
++ SM_FILE_T *f = (SM_FILE_T *)map->map_db1;
++
++ if (tTd(38, 20))
++ sm_dprintf("socket_map_lookup(%s, %s) %s\n",
++ map->map_mname, name, map->map_file);
++
++ nettolen = strlen(map->map_mname) + 1 + strlen(name);
++ if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
++ nettolen, map->map_mname, name) == SM_IO_EOF) || (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
++ (sm_io_error(f)))
++ {
++ syserr("socket_map_lookup(%s): failed to send lookup request",
++ map->map_mname);
++ *statp = EX_TEMPFAIL;
++ socket_map_close(map);
++ }
++ else
++ {
++ size_t replylen;
++
++ if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
++ {
++ syserr("socket_map_lookup(%s): failed to read length parameter of reply",
++ map->map_mname);
++ *statp = EX_TEMPFAIL;
++ socket_map_close(map);
++ }
++ else
++ {
++ /* XXX arbitrary limit for sanity */
++ if (replylen > 1000000)
++ {
++ syserr("socket_map_lookup(%s): reply too long: %u",
++ map->map_mname, replylen);
++ /* *statp = EX_PROTOCOL; */
++ *statp = EX_TEMPFAIL;
++ socket_map_close(map);
++ }
++ else
++ {
++ if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
++ {
++ syserr("socket_map_lookup(%s): missing ':' in reply",
++ map->map_mname);
++ /* *statp = EX_PROTOCOL; */
++ *statp = EX_TEMPFAIL;
++ }
++ else
++ {
++ size_t recvlen;
++ char *replybuf = (char *) sm_malloc(replylen + 1);
++ recvlen = sm_io_read(f, SM_TIME_DEFAULT,
++ replybuf, replylen);
++ if (recvlen < replylen)
++ {
++ syserr("socket_map_lookup(%s): received only %u of %u reply characters",
++ map->map_mname, recvlen, replylen);
++ *statp = EX_TEMPFAIL;
++ socket_map_close(map);
++ }
++ else
++ {
++ if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
++ {
++ syserr("socket_map_lookup(%s): missing ',' in reply",
++ map->map_mname);
++ /* *statp = EX_PROTOCOL; */
++ *statp = EX_TEMPFAIL;
++ socket_map_close(map);
++ }
++ else
++ {
++ char *value;
++ char *status = replybuf;
++
++ replybuf[recvlen] = '\0';
++ value = strchr(replybuf, ' ');
++ if (value != NULL)
++ {
++ *value = '\0';
++ value++;
++ }
++
++ if (strcmp(status, "OK") == 0)
++ {
++ *statp = EX_OK;
++
++ /* collect the return value */
++ if (bitset(MF_MATCHONLY, map->map_mflags))
++ rval = map_rewrite(map, name, strlen(name), NULL);
++ else
++ rval = map_rewrite(map, value, strlen(value), av);
++ }
++ else if(strcmp(status, "NOTFOUND") == 0)
++ {
++ *statp = EX_NOTFOUND;
++ if (tTd(38, 20))
++ sm_dprintf("socket_map_lookup(%s): %s not found\n",
++ map->map_mname, name);
++ }
++ else
++ {
++ if (tTd(38, 5))
++ sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
++ map->map_mname, name, status,
++ value ? value : "");
++ if ((strcmp(status, "TEMP") == 0) ||
++ (strcmp(status, "TIMEOUT") == 0))
++ {
++ *statp = EX_TEMPFAIL;
++ }
++ else if(strcmp(status, "PERM") == 0)
++ {
++ *statp = EX_UNAVAILABLE;
++ }
++ else
++ {
++ *statp = EX_PROTOCOL;
++ }
++ }
++ }
++ }
++
++ sm_free(replybuf);
++ }
++ }
++ }
++ }
++
++ return rval;
++}
++
++
++#endif /* SOCKETMAP */
+Index: sendmail/sendmail/sendmail/sendmail.h
+diff -u sendmail/sendmail/sendmail/sendmail.h:1.1.1.2 sendmail/sendmail/sendmail/sendmail.h:1.3
+--- sendmail/sendmail.h Thu Jan 23 11:50:27 2003
++++ sendmail/sendmail.h Thu Jan 23 11:51:38 2003
+@@ -1382,6 +1382,9 @@
+ #if LDAPMAP
+ MAP *sv_lmap; /* Maps for LDAP connection */
+ #endif /* LDAPMAP */
++#if SOCKETMAP
++ MAP *sv_socketmap; /* Maps for SOCKET connection */
++#endif /* SOCKETMAP */
+ #if MILTER
+ struct milter *sv_milter; /* milter filter name */
+ #endif /* MILTER */
+@@ -1413,8 +1416,12 @@
+ #endif /* MILTER */
+ #define ST_QUEUE 15 /* a queue entry */
+
++#if SOCKETMAP
++# define ST_SOCKETMAP 16 /* List head of maps for SOCKET connection */
++#endif /* SOCKETMAP */
++
+ /* This entry must be last */
+-#define ST_MCI 16 /* mailer connection info (offset) */
++#define ST_MCI 17 /* mailer connection info (offset) */
+
+ #define s_class s_value.sv_class
+ #define s_address s_value.sv_addr
+@@ -1432,6 +1439,9 @@
+ #if LDAPMAP
+ # define s_lmap s_value.sv_lmap
+ #endif /* LDAPMAP */
++#if SOCKETMAP
++# define s_socketmap s_value.sv_socketmap
++#endif /* SOCKETMAP */
+ #if MILTER
+ # define s_milter s_value.sv_milter
+ #endif /* MILTER */
+Index: sendmail/sendmail/sendmail/stab.c
+diff -u sendmail/sendmail/sendmail/stab.c:1.1.1.1 sendmail/sendmail/sendmail/stab.c:1.2
+--- sendmail/stab.c Fri Oct 11 14:44:04 2002
++++ sendmail/stab.c Wed Jan 22 18:57:22 2003
+@@ -173,6 +173,12 @@
+ len = sizeof s->s_quegrp;
+ break;
+
++#if SOCKETMAP
++ case ST_SOCKETMAP:
++ len = sizeof s->s_socketmap;
++ break;
++#endif /* SOCKETMAP */
++
+ default:
+ /*
+ ** Each mailer has its own MCI stab entry: