Subject: Patchset to ease setup of IP based virtual servers

From: Eugene Crosser <[email-masked]>
Date: 22 Jul 2002 15:50:04 +0400

Matti,

I have installed the version modified according to the attached diff in
production, it seems to work as expected so far.  Two major things in
this patch are:

1. if ZCONFIG unix environment is set, it is used as path to Zmailer
environment file.

2. If there is BINDADDR zenvironment variable, it is used do define
local address to bind to.  This has effect on smtpserver, smtp transport
and scheduler (with respect to mailq socket).

I have also included several minor diffs that I consider bugfixes.  You
are welcome to drop or reimplement any parts you think inappropriate (or
hint me how to redo them).  The minor fixes are:

1. "MANDIR" is "mandir" in autoconf.  You can set this path on
./configure stage like this: "--mandir=/usr/local/man".  This affects
SiteConfig.in and man/Makefile.in

2. error message missed carriage return in scheduler/mailq.c

3. smtpserver tried to report whoson information before it was obtained,
meaningless report removed in smtpserver/smtpserver.c

4. with USE_TRANSLATION, smtpserver tried to report error to the peer
before SS was sufficiently initialized.  This led to busylooping. 
Corresponding type()/typeflush() removed.

5. transports/smtp/smtp.c was reporting DNS misconfiguration with
LOG_ERR which I feel is pointless (this is something that *we* can *not*
fix), and on Solaris lead to flood of messages filling up serial console
(this cannot be switched off) and causing syslog problems because serial
console is only 9600 baud.  LOG_ERR changed to LOG_NOTICE.

Please consider applying all or parts of this.

Eugene
Index: SiteConfig.in
===================================================================
RCS file: /cvsroot/zmailer/SiteConfig.in,v
retrieving revision 1.13
diff -u -r1.13 SiteConfig.in
--- SiteConfig.in	2002/02/11 15:12:07	1.13
+++ SiteConfig.in	2002/07/22 11:17:35
@@ -63,7 +63,7 @@
 
 # MANDIR is the top of the manual directory hierarchy where manual pages
 # for the ZMailer programs are installed.  Usually /usr/man or /local/man.
-MANDIR=		@MANDIR@
+MANDIR=		@mandir@
 
 # LIBRARYDIR is the place for storing  libzmailer.a, which can be used to
 # create programs which use Zmailer's  zmailer(3) (aka: mail(3)) -library.
@@ -267,3 +267,12 @@
 # Some sites (well, one FUNET site), has LISTSERV, this is for
 # configuring that subpart of the  aliases.cf  scripts:
 #LISTSERV=/v/net/listserv.funet.fi
+
+# If defined, BINDADDR specifies to which local interface to bind
+# smtpserver, smtp transport agent and scheduler
+# Possible specification formats are:
+#    [0.0.0.0]
+#    [IPv6.0::0]
+#    iface:eth0:1
+#BINDADDR=iface:eth0:1
+BINDADDR="@BINDADDR@"
Index: configure.in
===================================================================
RCS file: /cvsroot/zmailer/configure.in,v
retrieving revision 1.112
diff -u -r1.112 configure.in
--- configure.in	2002/07/05 10:25:04	1.112
+++ configure.in	2002/07/22 11:17:36
@@ -432,6 +432,18 @@
 fi
 AC_MSG_RESULT([Using ZMailer SELFADDRESSES: $SELFADDRESSES])
 
+oldBINDADDR="$BINDADDR"
+AC_SUBST(BINDADDR)
+AC_ARG_WITH(bindaddr,   [  --with-bindaddr=SPEC    Bind to specific local interface
+                          possible format: [0.0.0.0], [IPv6.0::0], iface:eth0:1],
+        use_bindaddr=1)
+if test "x$use_bindaddr" != "x" ; then
+    BINDADDR="$withval"
+else
+    BINDADDR="$oldBINDADDR"
+fi
+AC_MSG_RESULT([Using ZMailer BINDADDR: $BINDADDR])
+
 sleep 2  # Sleep a bit here too
 
 AC_SUBST(LIBMALLOC)
Index: doc/guides/configure
===================================================================
RCS file: /cvsroot/zmailer/doc/guides/configure,v
retrieving revision 1.5
diff -u -r1.5 configure
--- doc/guides/configure	2000/10/10 21:00:57	1.5
+++ doc/guides/configure	2002/07/22 11:17:37
@@ -41,6 +41,7 @@
 	SENDMAILPATH=
 	RMAILPATH=
 	SELFADDRESSES=
+	BINDADDR=
 
 Options:
 
@@ -228,3 +229,8 @@
 	--with-privatembox
 		Use "private/" in a part of mailbox program module
 		compilarions. (Specifically: sieve.c)
+
+	--with-bindaddr="spec"
+		bind smtpserver, smtp tranport and scheduler (mailq
+		socket) to a specific address or interface as specified
+		by "spec".
Index: doc/manual/zinstall.sgml
===================================================================
RCS file: /cvsroot/zmailer/doc/manual/zinstall.sgml,v
retrieving revision 1.24
diff -u -r1.24 zinstall.sgml
--- doc/manual/zinstall.sgml	2002/02/12 13:49:20	1.24
+++ doc/manual/zinstall.sgml	2002/07/22 11:17:37
@@ -1734,6 +1734,7 @@
   SENDMAILPATH=
   RMAILPATH=
   SELFADDRESSES=
+  BINDADDR=
 </SCREEN>
 </PARA>
 
@@ -2688,6 +2689,23 @@
 # Some sites (well, one FUNET site), has LISTSERV, this is for
 # configuring that subpart of the  aliases.cf  scripts:
 #LISTSERV=/v/net/listserv.funet.fi
+
+</PARA></LISTITEM></VARLISTENTRY>
+
+
+<VARLISTENTRY>
+<TERM><VARNAME>BINDADDR</>=</TERM>
+<LISTITEM><PARA>
+
+# If defined, BINDADDR specifies to which local interface to bind
+# smtpserver, smtp transport agent and scheduler
+# Possible specification formats are:
+#    [0.0.0.0]
+#    [IPv6.0::0]
+#    iface:eth0:1
+#BINDADDR=iface:eth0:1
+BINDADDR="@BINDADDR@"
+
 
 </PARA></LISTITEM></VARLISTENTRY>
 </VARIABLELIST>
Index: include/libc.h
===================================================================
RCS file: /cvsroot/zmailer/include/libc.h,v
retrieving revision 1.11
diff -u -r1.11 libc.h
--- include/libc.h	2002/02/11 15:12:10	1.11
+++ include/libc.h	2002/07/22 11:17:37
@@ -24,7 +24,6 @@
 extern int getdtablesize __((void));
 
 /* getzenv.c */
-extern int         readzenv __((const char *file));
 extern const char *getzenv  __((const char *variable));
 
 /* mail.c */
Index: include/libz.h
===================================================================
RCS file: /cvsroot/zmailer/include/libz.h,v
retrieving revision 1.20
diff -u -r1.20 libz.h
--- include/libz.h	2002/07/11 11:42:00	1.20
+++ include/libz.h	2002/07/22 11:17:37
@@ -159,6 +159,9 @@
 /* zgetifaddress.c */
 extern int zgetifaddress __((int af, const char *ifname, Usockaddr *));
 
+/* zgetbindaddr.c */
+extern int zgetbindaddr __((char *ifname, Usockaddr *));
+
 /* splay.c */
 /* .... much ... in  "splay.h" */
 
Index: include/mail.h.in
===================================================================
RCS file: /cvsroot/zmailer/include/mail.h.in,v
retrieving revision 1.11
diff -u -r1.11 mail.h.in
--- include/mail.h.in	2001/07/29 18:21:39	1.11
+++ include/mail.h.in	2002/07/22 11:17:37
@@ -86,10 +86,6 @@
 
 /* These following are declared in order they are in prespective files */
 
-/* getzenv.c */
-extern int         readzenv __((const char *file));
-extern const char *getzenv  __((const char *variable));
-
 /* mail.c */
 extern const char * postoffice;
 extern int    mail_priority;
Index: lib/Makefile.in
===================================================================
RCS file: /cvsroot/zmailer/lib/Makefile.in,v
retrieving revision 1.12
diff -u -r1.12 Makefile.in
--- lib/Makefile.in	2002/06/18 10:22:30	1.12
+++ lib/Makefile.in	2002/07/22 11:17:37
@@ -27,7 +27,7 @@
 	strmatch.o nobody.o pwdgrp.o dottedquad.o hostent.o \
 	emalloc.o cfgets.o selfaddrs.o skip821address.o \
 	taspoolid.o strlower.o strupper.o pjwhash32.o crc32.o \
-	parseintv.o zgetifaddress.o sleepycatdb.o
+	parseintv.o zgetifaddress.o zgetbindaddr.o sleepycatdb.o
 SOURCE=	esyslib.c stringlib.c rfc822date.c detach.c \
 	killprev.c linebuffer.c loginit.c die.c \
 	ranny.c trusted.c allocate.c prversion.c \
@@ -35,7 +35,7 @@
 	strmatch.c nobody.c pwdgrp.c dottedquad.c hostent.c \
 	emalloc.c cfgets.c selfaddrs.c skip821address.c \
 	taspoolid.c strlower.c strupper.c pjwhash32.c crc32.c \
-	parseintv.c zgetifaddress.c sleepycatdb.c
+	parseintv.c zgetifaddress.c zgetbindaddr.c sleepycatdb.c
 
 all $(LIBNAME).a: $(TOPDIR)/libs/$(LIBNAME).a
 
Index: libc/getzenv.c
===================================================================
RCS file: /cvsroot/zmailer/libc/getzenv.c,v
retrieving revision 1.5
diff -u -r1.5 getzenv.c
--- libc/getzenv.c	2001/01/15 15:12:04	1.5
+++ libc/getzenv.c	2002/07/22 11:17:37
@@ -27,13 +27,26 @@
 static char *zenviron = NULL;
 static int zenvlen = 0;
 
-int
-readzenv(file)
-	const char *file;
+static int readzenv __((void));
+
+static int
+readzenv(void)
 {
+	char *file;
 	int fd;
 	struct stat stbuf;
 
+	if ((file=getenv("ZCONFIG"))) {
+	  if ((getuid() != geteuid()) && (access(file,R_OK) != 0)) {
+	    fprintf(stderr, "attempt to use config file %s that is "
+				"not readable by the invoker of setuid "
+				"program prevented! (uid=%d, euid=%d)\n",
+		file,getuid(),geteuid());
+	    file=ZMAILER_ENV_FILE;
+	  }
+	} else
+	  file=ZMAILER_ENV_FILE;
+
 	fd = open(file, 0);
 	if (fd < 0) {
 	  fprintf(stderr, "%s: open: %s: %s\n",
@@ -86,7 +99,7 @@
 
 	len = zenvlen;
 	if (len <= 0) {
-	  if (!readzenv(ZMAILER_ENV_FILE))
+	  if (!readzenv())
 	    return NULL;
 	  len = zenvlen;
 	  if (len <= 0)
Index: man/Makefile.in
===================================================================
RCS file: /cvsroot/zmailer/man/Makefile.in,v
retrieving revision 1.22
diff -u -r1.22 Makefile.in
--- man/Makefile.in	2002/02/22 11:07:03	1.22
+++ man/Makefile.in	2002/07/22 11:17:37
@@ -6,8 +6,8 @@
 # VPATH = @srcdir@ ## NO VPATH HERE!
 @SET_MAKE@
 
-#prefix=	@prefix@
-MANDIR=		${prefix}@mandir@
+prefix=		@prefix@
+MANDIR=		@mandir@
 TOPDIR=		..
 S=		$(srcdir)
 INSTALL=	@INSTALL@
Index: proto/zmailer.sh.in
===================================================================
RCS file: /cvsroot/zmailer/proto/zmailer.sh.in,v
retrieving revision 1.18
diff -u -r1.18 zmailer.sh.in
--- proto/zmailer.sh.in	2001/10/16 20:29:23	1.18
+++ proto/zmailer.sh.in	2002/07/22 11:17:37
@@ -35,7 +35,8 @@
 fi
 FLAGS="defaults 50"
 
-ZCONFIG=@ZMAILERCFGFILE@
+ZCONFIG=${ZCONFIG:-@ZMAILERCFGFILE@}
+export ZCONFIG
 
 # Sense how the  echo  works, it is either, or..
 # There are POSIX echos, SysV echos, BSD echos...
Index: scheduler/mailq.c
===================================================================
RCS file: /cvsroot/zmailer/scheduler/mailq.c,v
retrieving revision 1.64
diff -u -r1.64 mailq.c
--- scheduler/mailq.c	2002/01/24 22:18:47	1.64
+++ scheduler/mailq.c	2002/07/22 11:17:37
@@ -446,7 +446,7 @@
 	    if (rc < 0) {
 	      eval = errno;
 	      close(fd);
-	      fprintf(stderr, "%s: connect failed to %s",
+	      fprintf(stderr, "%s: connect failed to %s\n",
 		      progname, ai->ai_canonname ? ai->ai_canonname : host);
 	      fd = -1;
 	      continue;
@@ -455,7 +455,7 @@
 	  if (fd >= 0)
 	    docat((char *)NULL, fd);
 	  else {
-	    fprintf(stderr, "%s: connect failed to %s",
+	    fprintf(stderr, "%s: connect failed to %s\n",
 		    progname, host);
 	  }
 	}
Index: scheduler/transport.c
===================================================================
RCS file: /cvsroot/zmailer/scheduler/transport.c,v
retrieving revision 1.105
diff -u -r1.105 transport.c
--- scheduler/transport.c	2002/05/16 18:09:10	1.105
+++ scheduler/transport.c	2002/07/22 11:17:38
@@ -1498,9 +1498,10 @@
 	    if (modedata2)  modedata2[-1] = '@';
 
 	    memset(&ua, 0, sizeof(ua));
+	    if (zgetbindaddr(NULL, &ua))
+		ua.v4.sin_addr.s_addr = htonl(INADDR_ANY);
 	    ua.v4.sin_port        = htons(port);
 	    ua.v4.sin_family      = AF_INET;
-	    ua.v4.sin_addr.s_addr = htonl(INADDR_ANY);
 	    querysocket = -1;
 #ifdef INET6
 	    querysocket = socket(PF_INET6, SOCK_STREAM, 0);
@@ -1510,6 +1511,8 @@
 #ifdef INET6
 	    else {
 	      memset(&ua, 0, sizeof(ua));
+	      if (zgetbindaddr(NULL, &ua))
+		  ua.v4.sin_addr.s_addr = htonl(INADDR_ANY);
 	      ua.v6.sin6_port   = htons(port);
 	      ua.v6.sin6_family = AF_INET6;
 	    }
Index: smtpserver/cfgread.c
===================================================================
RCS file: /cvsroot/zmailer/smtpserver/cfgread.c,v
retrieving revision 1.40
diff -u -r1.40 cfgread.c
--- smtpserver/cfgread.c	2002/07/11 11:41:57	1.40
+++ smtpserver/cfgread.c	2002/07/22 11:17:38
@@ -17,6 +17,8 @@
 #define SKIPTEXT(Y)  while (*Y && *Y != ' ' && *Y != '\t') ++Y
 #define SKIPDIGIT(Y) while ('0' <= *Y && *Y <= '9') ++Y
 
+static int called_getbindaddr = 0;
+
 static void dollarexpand __((unsigned char *s0, int space));
 static void dollarexpand(s0, space)
      unsigned char *s0;
@@ -208,50 +210,8 @@
       if (bindport != 0 && bindport != 0xFFFFU)
 	bindport_set = 1;
     } else if (cistrcmp(name, "BindAddress") == 0 && param1) {
-      memset(&bindaddr, 0, sizeof(bindaddr));
-      bindaddr_set = 1;
-#if defined(AF_INET6) && defined(INET6)
-      if (cistrncmp(param1,"[ipv6 ",6) == 0 ||
-	  cistrncmp(param1,"[ipv6:",6) == 0 ||
-	  cistrncmp(param1,"[ipv6.",6) == 0) {
-	char *s = strchr(param1,']');
-	if (s) *s = 0;
-	if (inet_pton(AF_INET6, param1+6, &bindaddr.v6.sin6_addr) < 1) {
-	  /* False IPv6 number literal */
-	  /* ... then we don't set the IP address... */
-	  bindaddr_set = 0;
-	}
-	bindaddr.v6.sin6_family = AF_INET6;
-      } else
-#endif
-	if (*param1 == '[') {
-	  char *s = strchr(param1,']');
-	  if (s) *s = 0;
-	  if (inet_pton(AF_INET, param1+1, &bindaddr.v4.sin_addr) < 1) {
-	    /* False IP(v4) number literal */
-	    /* ... then we don't set the IP address... */
-	    bindaddr_set = 0;
-	  }
-	  bindaddr.v4.sin_family = AF_INET;
-	} else {
-	  if (CISTREQN(param1,"iface:",6)) {
-#if defined(AF_INET6) && defined(INET6)
-	    bindaddr.v6.sin6_family = AF_INET6;
-	    if (zgetifaddress(AF_INET6, param1+6, &bindaddr))
-	      /* Didn't get IPv6 interface address of given name.. */
-#endif
-	      {
-		if (zgetifaddress(AF_INET, param1+6, &bindaddr)) {
-		  /* No recognized interface! */
-		  bindaddr_set = 0;
-		}
-	      }
-	  } else {
-	    /* XXX: TODO: Try to see if this is an interface name, and pick
-	       IPv4 and/or IPv6 addresses for that interface. */
-	    bindaddr_set = 0;
-	  }
-	}
+	called_getbindaddr=1;
+	bindaddr_set = !zgetbindaddr(param1,&bindaddr);
     }
 
     /* SMTP Protocol limit & policy tune options */
@@ -516,6 +476,8 @@
 	configuration_ok = 1; /* At least something! */
     }
     fclose(fp);
+    if (!called_getbindaddr)
+	bindaddr_set = !zgetbindaddr(NULL,&bindaddr);
     return head;
 }
 
Index: smtpserver/smtpserver.c
===================================================================
RCS file: /cvsroot/zmailer/smtpserver/smtpserver.c,v
retrieving revision 1.123
diff -u -r1.123 smtpserver.c
--- smtpserver/smtpserver.c	2002/05/28 11:18:13	1.123
+++ smtpserver/smtpserver.c	2002/07/22 11:17:39
@@ -757,25 +757,15 @@
 		" [port %d]", SS.rport);
 
 	if (smtp_syslog && ident_flag) {
-#ifdef HAVE_WHOSON_H
-	    zsyslog((LOG_INFO, "connection from %s@%s (whoson: $s)\n",
-		     SS.ident_username, SS.rhostname, SS.whoson_data));
-#else
 	    zsyslog((LOG_INFO, "connection from %s@%s\n",
 		     SS.ident_username, SS.rhostname));
-#endif
 	}
 
 	pid = getpid();
 	settrusteduser();	/* dig out the trusted user ID */
 	openlogfp(&SS, daemon_flg);
-#ifdef HAVE_WHOSON_H
-	type(NULL,0,NULL,"connection from %s:%d ident: %s whoson: %s",
-	     SS.rhostname, SS.rport, SS.ident_username, SS.whoson_data);
-#else
 	type(NULL,0,NULL,"connection from %s:%d ident: %s",
 	     SS.rhostname, SS.rport, SS.ident_username);
-#endif
 
 #if 0
 	SIGNAL_HANDLE(SIGCHLD, SIG_DFL);
@@ -1919,8 +1909,11 @@
     }
     if (!(*lang) || (X_settrrc < 0)) {
 	/* we don't know our codetable, hush client away */
+	/* Oops!  With version 2.99.56-pre1 you cannot use type()
+	   before some initialization of SS is performed!
 	type(SS, 451, NULL, "Server could not setup translation.", NULL);
 	typeflush(SS);
+	*/
 	sleep(2);
 	exit(0);
 #endif				/* USE_TRANSLATION */
Index: transports/smtp/smtp.c
===================================================================
RCS file: /cvsroot/zmailer/transports/smtp/smtp.c,v
retrieving revision 1.266
diff -u -r1.266 smtp.c
--- transports/smtp/smtp.c	2002/07/11 11:42:00	1.266
+++ transports/smtp/smtp.c	2002/07/22 11:17:39
@@ -2505,7 +2505,7 @@
 		  sprintf(SS->remotemsg,
 			  "smtp; 500 (nameserver data inconsistency. All MXes rejected [we are the best?], no address: '%.200s')", host);
 #if 1
-		  zsyslog((LOG_ERR, "%s", SS->remotemsg));
+		  zsyslog((LOG_NOTICE, "%s", SS->remotemsg));
 		  if (r != EX_TEMPFAIL)
 		    r = EX_NOHOST;
 #endif
@@ -2513,7 +2513,7 @@
 		  sprintf(SS->remotemsg,
 			  "smtp; 500 (nameserver data inconsistency. No MX, no address: '%.200s' (%s))",
 			  host, gai_err == EAI_NONAME ? "NONAME" : "NODATA");
-		  zsyslog((LOG_ERR, "%s r=%d", SS->remotemsg, r));
+		  zsyslog((LOG_NOTICE, "%s r=%d", SS->remotemsg, r));
 #if 0
 		  if (r != EX_TEMPFAIL)
 		    r = EX_NOHOST; /* Can do instant reject */
@@ -2525,7 +2525,7 @@
 			  "smtp; 500 (nameserver data inconsistency. No MX, no address: '%.200s', errno=%s, gai_errno='%s')",
 			  host, strerror(errno), gai_strerror(gai_err));
 #if 1
-		  zsyslog((LOG_ERR, "%s", SS->remotemsg));
+		  zsyslog((LOG_NOTICE, "%s", SS->remotemsg));
 		  r = EX_TEMPFAIL; /* This gives delayed rejection (after a timeout) */
 #endif
 		}
@@ -2845,12 +2845,9 @@
 	int af, port;
 	volatile int addrsiz;
 	int sk;
-	struct sockaddr_in *sai = (struct sockaddr_in *)sa;
-	struct sockaddr_in sad;
-#if defined(AF_INET6) && defined(INET6)
-	struct sockaddr_in6 *sai6 = (struct sockaddr_in6 *)sa;
-	struct sockaddr_in6 sad6;
-#endif
+	Usockaddr *sai = (Usockaddr *)sa;
+	Usockaddr sad;
+	int wantbindaddr = 0;
 	Usockaddr upeername;
 	int upeernamelen = 0;
 
@@ -2866,15 +2863,14 @@
 	af = sa->sa_family;
 #if defined(AF_INET6) && defined(INET6)
 	if (sa->sa_family == AF_INET6) {
-	  addrsiz = sizeof(*sai6);
-	  memset(&sad6, 0, sizeof(sad6));
+	  addrsiz = sizeof(sad.v6);
 	}
 	else
 #endif
 	  {
-	    addrsiz = sizeof(*sai);
-	    memset(&sad, 0, sizeof(sad));
+	    addrsiz = sizeof(sad.v4);
 	  }
+	memset(&sad, 0, sizeof(sad));
 
 	if (conndebug)
 	  fprintf(stderr, "Trying %.200s [%.200s] ... ",
@@ -2907,93 +2903,22 @@
 	  return EX_TEMPFAIL;
 	}
 
-	if (localidentity != NULL) {
-	  /* Uh... Somebody wants us to do special hoops...
-	     ... to bind some of our alternate IP addresses,
-	     for example.. */
-	  if (0)
-	    ;
-#if defined(AF_INET6) && defined(INET6)
-	  else if (af == AF_INET6 &&
-		   CISTREQN(localidentity,"iface:",6)) {
-	    zgetifaddress(af, localidentity+6, (Usockaddr *)&sad6);
-	  }
-	  else if (CISTREQN(localidentity,"[ipv6 ",6)  ||
-		   CISTREQN(localidentity,"[ipv6:",6)  ||
-		   CISTREQN(localidentity,"[ipv6.",6) ) {
-	    char *s = strchr(localidentity,']');
-	    if (s) *s = 0;
-	    if (inet_pton(AF_INET6, localidentity+6, &sad6.sin6_addr) < 1) {
-	      /* False IPv6 number literal */
-	      /* ... then we don't set the IP address... */
-	    }
-	  }
-#endif /* AF_INET6 && INET6 */
-	  else if (af == AF_INET &&
-		   CISTREQN(localidentity,"iface:",6)) {
-	    zgetifaddress(af, localidentity+6, (Usockaddr *)&sad);
-	  }
-	  else if (*localidentity == '[') {
-	    char *s = strchr(localidentity,']');
-	    if (s) *s = 0;
-	    if (inet_pton(AF_INET, localidentity+1, &sad.sin_addr) < 1) {
-	      /* False IP(v4) number literal */
-	      /* ... then we don't set the IP address... */
-	    }
-	  } else {
-	    struct addrinfo req, *ai = NULL;
-	    int r2;
+	wantbindaddr = !zgetbindaddr(localidentity,&sad); 
 
-	    memset(&req, 0, sizeof(req));
-	    req.ai_socktype = SOCK_STREAM;
-	    req.ai_protocol = IPPROTO_TCP;
-	    req.ai_flags    = AI_CANONNAME;
-	    req.ai_family   = sa->sa_family; /* Same family, as our
-						destination address is */
-#ifdef HAVE_GETADDRINFO
-	    r2 = getaddrinfo(localidentity, "0", &req, &ai);
-#else
-	    r2 = _getaddrinfo_(localidentity, "0", &req, &ai, SS->verboselog);
-#endif
-	    if (SS->verboselog)
-	      fprintf(SS->verboselog,"getaddrinfo(%s,'%s') -> r=%d, ai=%p\n",
-		      sa->sa_family == PF_INET ? "INET":"INET6",
-		      localidentity,r2,ai);
-	    if (r2 == 0 && ai != NULL) /* We try ONLY the first address. */ {
-	      if (ai->ai_family == AF_INET) {
-		memcpy((void*)&sad.sin_addr,
-		       (void*)&((struct sockaddr_in*)ai->ai_addr)->sin_addr,
-		       4);
-	      }
-#if defined(AF_INET6) && defined(INET6)
-	      else {
-		memcpy((void*)&sad6.sin6_addr,
-		       (void*)&((struct sockaddr_in6*)ai->ai_addr)->sin6_addr,
-		       16);
-	      }
-#endif
-	    }
-	    if (ai != NULL)
-	      freeaddrinfo(ai);
-	    /* If it didn't resolv, */
-	    /* ... then we don't set the IP address... */
-	  }
-	}
-
 	if (wantreserved && getuid() == 0) {
 	  /* try grabbing a port */
 	  for (p = IPPORT_RESERVED-1; p >= (u_short)(IPPORT_RESERVED/2); --p) {
 	    if (af == AF_INET) {
-	      sad.sin_family = AF_INET;
-	      sad.sin_port   = htons(p);
-	      if (bind(sk, (struct sockaddr *)&sad, sizeof sad) >= 0)
+	      sad.v4.sin_family = AF_INET;
+	      sad.v4.sin_port   = htons(p);
+	      if (bind(sk, (struct sockaddr *)&sad, sizeof sad.v4) >= 0)
 		break;
 	    }
 #if defined(AF_INET6) && defined(INET6)
 	    else if (af == AF_INET6) {
-	      sad6.sin6_family = AF_INET6;
-	      sad6.sin6_port   = htons(p);
-	      if (bind(sk, (struct sockaddr *)&sad6, sizeof sad6) >= 0)
+	      sad.v6.sin6_family = AF_INET6;
+	      sad.v6.sin6_port   = htons(p);
+	      if (bind(sk, (struct sockaddr *)&sad, sizeof sad.v6) >= 0)
 		break;
 	    }
 #endif
@@ -3026,15 +2951,15 @@
 	      fprintf(logfp,"%s#\t(Internal error, too many busy ports)\n", logtag());
 	    return EX_TEMPFAIL;
 	  }
-	} else if (localidentity != NULL) {
+	} else if (wantbindaddr) {
 	  /* Ok, it wasn't a desire for any PRIVILEGED port, just
 	     binding on the specific IP will be accepted. */
 	  errno = 0;
 	  if (af == AF_INET)
-	    bind(sk, (struct sockaddr *)&sad, sizeof sad);
+	    bind(sk, (struct sockaddr *)&sad, sizeof sad.v4);
 #if defined(AF_INET6) && defined(INET6)
 	  if (af == AF_INET6)
-	    bind(sk, (struct sockaddr *)&sad6, sizeof sad6);
+	    bind(sk, (struct sockaddr *)&sad, sizeof sad.v6);
 #endif
 	  if (logfp)
 	    fprintf(logfp,"%s#\tlocalidentity=%s bind() errno = %d\n",
@@ -3046,17 +2971,17 @@
 	if (SS->literalport > 0)
 	  port = SS->literalport;
 	if (af == AF_INET)
-	  sai->sin_port   = htons(port);
+	  sai->v4.sin_port   = htons(port);
 #if defined(AF_INET6) && defined(INET6)
 	if (af == AF_INET6)
-	  sai6->sin6_port = htons(port);
+	  sai->v6.sin6_port = htons(port);
 #endif
 	/* setreuid(0,first_uid);
 	   if(SS->verboselog) fprintf(SS->verboselog,"setreuid: first_uid=%d, ruid=%d, euid=%d\n",first_uid,getuid(),geteuid()); */
 
 	if (SS->verboselog)
 	  fprintf(SS->verboselog, "Connecting to %.200s [%.200s] port %d\n",
-		  hostname, SS->ipaddress, ntohs(sai->sin_port));
+		  hostname, SS->ipaddress, ntohs(sai->v4.sin_port));

 	gotalarm = 0;
@@ -3593,6 +3518,8 @@
 	char *status = NULL;
 	int statesave;
 	time_t when_timeout;
+
+	if (SS->smtpfd < 0) return rc;
 
 	SS->smtp_outcount = 0;
 	SS->block_written = 0;
Index: utils/rotate-logs.sh.in
===================================================================
RCS file: /cvsroot/zmailer/utils/rotate-logs.sh.in,v
retrieving revision 1.4
diff -u -r1.4 rotate-logs.sh.in
--- utils/rotate-logs.sh.in	2001/09/30 01:48:47	1.4
+++ utils/rotate-logs.sh.in	2002/07/22 11:17:39
@@ -7,7 +7,8 @@
 #  can be used weekly to monthly...
 #
 
-ZCONFIG=@ZMAILERCFGFILE@
+ZCONFIG=${ZCONFIG:-@ZMAILERCFGFILE@}
+export ZCONFIG
 . $ZCONFIG
 
 cd $LOGDIR
--- /dev/null	Thu Jul 18 17:15:00 2002
+++ lib/zgetbindaddr.c	Wed Jul 17 18:05:36 2002
@@ -0,0 +1,113 @@
+/*
+ * int zgetbindaddr(char *bindspec, Usockaddr *sap)
+ */
+
+/*
+    Parse first argument for the specification of IP v.4 or v.6
+    address or network interface.  If NULL or empty, fallback to
+    the value of 'BINDADDR' ZENV variable.  On success, return
+    zero, otherwise non-zero.  That is, if the caller gets zero
+    code, it should bind() to the address returned in *sap, else
+    bind to INADDR_ANY.
+
+    Possible specification formats are:
+	[0.0.0.0]
+	[IPv6.0::0]
+	iface:eth0:1
+
+    Original copyright by Matti Aarnio <[email-masked]> 1997,2000,
+    modifications by Eugene Crosser <[email-masked]> 2002
+*/
+
+#include "hostenv.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <sys/ioctl.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_IN6_H
+# include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETINET6_IN6_H
+# include <netinet6/in6.h>
+#endif
+#ifdef HAVE_LINUX_IN6_H
+# include <linux/in6.h>
+#endif
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libc.h"
+#include "zmalloc.h"
+#include "libz.h"
+
+#include "hostenv.h"
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+int
+zgetbindaddr(bindspec, sap)
+	char *bindspec;
+	Usockaddr *sap;
+{
+	int result = 0;
+
+	if ((bindspec == NULL) || (*bindspec == '\0'))
+		bindspec=getzenv("BINDADDR");
+	if ((bindspec == NULL) || (*bindspec == '\0'))
+		return 1; /* not specified - bind to INADDR_ANY */
+
+#if defined(AF_INET6) && defined(INET6)
+	if (cistrncmp(bindspec, "[ipv6 ", 6) == 0 ||
+	    cistrncmp(bindspec, "[ipv6:", 6) == 0 ||
+	    cistrncmp(bindspec, "[ipv6.", 6) == 0) {
+		char *s = strchr(bindspec, ']');
+		if (s) *s = 0;
+		if (inet_pton
+		    (AF_INET6, bindspec + 6, &sap->v6.sin6_addr) < 1) {
+			/* False IPv6 number literal */
+			/* ... then we don't set the IP address... */
+			result = 1;
+		}
+		sap->v6.sin6_family = AF_INET6;
+	} else
+#endif
+	if (*bindspec == '[') {
+		char *s = strchr(bindspec, ']');
+		if (s) *s = 0;
+		if (inet_pton(AF_INET, bindspec + 1, &sap->v4.sin_addr)
+		    < 1) {
+			/* False IP(v4) number literal */
+			/* ... then we don't set the IP address... */
+			result = 1;
+		}
+		sap->v4.sin_family = AF_INET;
+	} else {
+		if (CISTREQN(bindspec, "iface:", 6)) {
+#if defined(AF_INET6) && defined(INET6)
+			sap->v6.sin6_family = AF_INET6;
+			if (zgetifaddress
+			    (AF_INET6, bindspec + 6, sap))
+				/* Didn't get IPv6 interface address of given name.. */
+#endif
+			{
+				if (zgetifaddress
+				    (AF_INET, bindspec + 6, sap)) {
+					/* No recognized interface! */
+					result = 1;
+				}
+			}
+		} else {
+			/* XXX: TODO: Try to see if this is an interface name, and pick
+			   IPv4 and/or IPv6 addresses for that interface. */
+			result = 1;
+		}
+	}
+	return result;
+}