This unfortunately doesn't really work with login_chroot=yes, which is why
it was never integrated.

Index: configure.in
===================================================================
RCS file: /var/lib/cvs/dovecot/configure.in,v
retrieving revision 1.273
diff -u -r1.273 configure.in
--- configure.in	9 Apr 2006 12:38:24 -0000	1.273
+++ configure.in	9 Apr 2006 17:09:10 -0000
@@ -64,6 +64,15 @@
 	notify=$withval,
 	notify=)
 
+AC_ARG_WITH(libwrap,
+[  --with-libwrap          Build with libwrap, ie. TCP-wrappers (default)],
+    if test x$withval = xno; then
+		want_libwrap=no
+	else
+		want_libwrap=yes
+	fi,
+	want_libwrap=yes)
+
 AC_ARG_WITH(passwd,
 [  --with-passwd           Build with /etc/passwd support (default)],
 	if test x$withval = xno; then
@@ -1265,6 +1274,20 @@
 fi
 
 dnl **
+dnl ** TCP wrappers
+dnl **
+
+if test "$want_libwrap" = "yes"; then
+  AC_CHECK_LIB(wrap, request_init, [
+    AC_CHECK_HEADER(tcpd.h, [
+      AC_DEFINE(HAVE_LIBWRAP,, Define if you have libwrap)
+      LIBWRAP_LIBS=-lwrap
+      AC_SUBST(LIBWRAP_LIBS)
+    ])
+  ])
+fi
+
+dnl **
 dnl ** userdb and passdb checks
 dnl **
 
Index: dovecot-example.conf
===================================================================
RCS file: /var/lib/cvs/dovecot/dovecot-example.conf,v
retrieving revision 1.190
diff -u -r1.190 dovecot-example.conf
--- dovecot-example.conf	9 Apr 2006 15:50:53 -0000	1.190
+++ dovecot-example.conf	9 Apr 2006 17:09:10 -0000
@@ -145,6 +145,11 @@
 # Greeting message for clients.
 #login_greeting = Dovecot ready.
 
+# Use TCP wrappers for incoming connection access checks. This requires that
+# Dovecot was compiled with libwrap. Note that this setting requires
+# login_process_per_connection=yes.
+#login_tcp_wrappers = no
+
 # Space-separated list of elements we want to log. The elements which have
 # a non-empty variable value are joined together to form a comma-separated
 # string.
Index: src/imap-login/Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap-login/Makefile.am,v
retrieving revision 1.5
diff -u -r1.5 Makefile.am
--- src/imap-login/Makefile.am	20 Oct 2004 23:05:54 -0000	1.5
+++ src/imap-login/Makefile.am	9 Apr 2006 17:09:10 -0000
@@ -13,7 +13,8 @@
 	../lib-imap/libimap.a \
 	../lib-auth/libauth.a \
 	../lib/liblib.a \
-	$(SSL_LIBS)
+	$(SSL_LIBS) \
+	$(LIBWRAP_LIBS)
 
 imap_login_SOURCES = \
 	client.c \
Index: src/login-common/main.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/login-common/main.c,v
retrieving revision 1.31
diff -u -r1.31 main.c
--- src/login-common/main.c	29 Jan 2006 12:14:49 -0000	1.31
+++ src/login-common/main.c	9 Apr 2006 17:09:10 -0000
@@ -18,8 +18,15 @@
 #include <unistd.h>
 #include <syslog.h>
 
+#ifdef HAVE_LIBWRAP
+#  include <tcpd.h>
+#  include <syslog.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif
+
 bool disable_plaintext_auth, process_per_connection, greeting_capability;
-bool verbose_proctitle, verbose_ssl, verbose_auth;
+bool verbose_proctitle, verbose_ssl, verbose_auth, tcp_wrappers;
 const char *greeting, *log_format;
 const char *const *log_format_elements;
 unsigned int max_logging_users;
@@ -79,6 +86,34 @@
 	io_loop_stop(ioloop);
 }
 
+static void access_check(int fd, const struct ip_addr *ip)
+{
+#ifdef HAVE_LIBWRAP
+	struct request_info req;
+
+	if (!tcp_wrappers || !process_per_connection) {
+		/* TCP wrappers may block while doing DNS lookups, which is
+		   bad if there are multiple connections within this
+		   process.. */
+		return;
+	}
+
+	request_init(&req,
+		     RQ_FILE, fd,
+		     RQ_CLIENT_ADDR, net_ip2addr(ip),
+		     RQ_DAEMON, process_name,
+		     0);
+	fromhost(&req);
+
+	if (!hosts_access(&req)) {
+		i_error("Connection refused by tcp-wrappers: %s",
+			net_ip2addr(ip));
+		refuse(&req);
+		i_unreached();
+	}
+#endif
+}
+
 static void login_accept(void *context __attr_unused__)
 {
 	struct ip_addr ip, local_ip;
@@ -90,6 +125,7 @@
 			i_fatal("accept() failed: %m");
 		return;
 	}
+	access_check(fd, &ip);
 
 	if (process_per_connection)
 		main_close_listen();
@@ -113,6 +149,7 @@
 			i_fatal("accept() failed: %m");
 		return;
 	}
+	access_check(fd, &ip);
 
 	if (process_per_connection)
 		main_close_listen();
@@ -182,6 +219,7 @@
 	verbose_proctitle = getenv("VERBOSE_PROCTITLE") != NULL;
         verbose_ssl = getenv("VERBOSE_SSL") != NULL;
         verbose_auth = getenv("VERBOSE_AUTH") != NULL;
+        tcp_wrappers = getenv("TCP_WRAPPERS") != NULL;
 
 	value = getenv("MAX_LOGGING_USERS");
 	max_logging_users = value == NULL ? 0 : strtoul(value, NULL, 10);
@@ -277,11 +315,12 @@
 	   restrict_access_by_env() is called */
 	lib_init();
 
+	process_name = strrchr(argv[0], '/');
+	process_name = process_name == NULL ? argv[0] : process_name+1;
+
 	if (is_inetd) {
 		/* running from inetd. create master process before
 		   dropping privileges. */
-		process_name = strrchr(argv[0], '/');
-		process_name = process_name == NULL ? argv[0] : process_name+1;
 		group_name = t_strcut(process_name, '-');
 
 		for (i = 1; i < argc; i++) {
Index: src/master/login-process.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/master/login-process.c,v
retrieving revision 1.72
diff -u -r1.72 login-process.c
--- src/master/login-process.c	9 Apr 2006 14:36:03 -0000	1.72
+++ src/master/login-process.c	9 Apr 2006 17:09:10 -0000
@@ -455,6 +455,8 @@
 	env_put(t_strconcat("LOG_FORMAT=", set->login_log_format, NULL));
 	if (set->login_greeting_capability)
 		env_put("GREETING_CAPABILITY=1");
+	if (set->login_tcp_wrappers)
+		env_put("TCP_WRAPPERS=1");
 }
 
 static pid_t create_login_process(struct login_group *group)
Index: src/master/master-settings.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/master/master-settings.c,v
retrieving revision 1.120
diff -u -r1.120 master-settings.c
--- src/master/master-settings.c	9 Apr 2006 15:50:53 -0000	1.120
+++ src/master/master-settings.c	9 Apr 2006 17:09:10 -0000
@@ -83,6 +83,7 @@
 	DEF(SET_BOOL, login_process_per_connection),
 	DEF(SET_BOOL, login_chroot),
 	DEF(SET_BOOL, login_greeting_capability),
+	DEF(SET_BOOL, login_tcp_wrappers),
 
 	DEF(SET_INT, login_process_size),
 	DEF(SET_INT, login_processes_count),
@@ -286,6 +287,7 @@
 	MEMBER(login_process_per_connection) TRUE,
 	MEMBER(login_chroot) TRUE,
 	MEMBER(login_greeting_capability) FALSE,
+	MEMBER(login_tcp_wrappers) FALSE,
 
 	MEMBER(login_process_size) 32,
 	MEMBER(login_processes_count) 3,
@@ -719,6 +721,19 @@
 		return FALSE;
 	}
 
+	if (!set->login_process_per_connection && set->login_tcp_wrappers) {
+		i_error("login_process_per_connection=no can't be used with "
+			"login_tcp_wrappers=yes");
+		return FALSE;
+	}
+#ifndef HAVE_LIBWRAP
+	if (set->login_tcp_wrappers) {
+		i_error("login_tcp_wrappers can't be used because "
+			"Dovecot wasn't built with libwrap");
+		return FALSE;
+	}
+#endif
+
 	return TRUE;
 }
 
Index: src/master/master-settings.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/master/master-settings.h,v
retrieving revision 1.79
diff -u -r1.79 master-settings.h
--- src/master/master-settings.h	9 Apr 2006 15:50:53 -0000	1.79
+++ src/master/master-settings.h	9 Apr 2006 17:09:10 -0000
@@ -48,6 +48,7 @@
 	bool login_process_per_connection;
 	bool login_chroot;
 	bool login_greeting_capability;
+	bool login_tcp_wrappers;
 
 	unsigned int login_process_size;
 	unsigned int login_processes_count;
Index: src/pop3-login/Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/pop3-login/Makefile.am,v
retrieving revision 1.5
diff -u -r1.5 Makefile.am
--- src/pop3-login/Makefile.am	20 Oct 2004 23:06:11 -0000	1.5
+++ src/pop3-login/Makefile.am	9 Apr 2006 17:09:10 -0000
@@ -11,7 +11,8 @@
 	../login-common/liblogin-common.a \
 	../lib-auth/libauth.a \
 	../lib/liblib.a \
-	$(SSL_LIBS)
+	$(SSL_LIBS) \
+	$(LIBWRAP_LIBS)
 
 pop3_login_SOURCES = \
 	client.c \
