--- src/global/mail_params.h.orig	Thu Jul 27 09:48:44 2006
+++ src/global/mail_params.h	Sun Aug 27 01:50:27 2006
@@ -1924,6 +1924,12 @@
 
 #define REJECT_UNAUTH_PIPE	"reject_unauth_pipelining"
 
+#define CONN_COUNT_LIMIT	"client_connection_count_limit"
+#define CONN_RATE_LIMIT		"client_connection_rate_limit"
+#define MAIL_RATE_LIMIT		"client_message_rate_limit"
+#define RCPT_RATE_LIMIT		"client_recipient_rate_limit"
+#define NTLS_RATE_LIMIT		"client_new_tls_session_rate_limit"
+
 #define VAR_SMTPD_NULL_KEY	"smtpd_null_access_lookup_key"
 #define DEF_SMTPD_NULL_KEY	"<>"
 extern char *var_smtpd_null_key;
--- src/smtpd/smtpd.c.orig	Tue Aug 22 22:53:52 2006
+++ src/smtpd/smtpd.c	Sun Aug 27 01:57:12 2006
@@ -1917,10 +1917,10 @@
     if (SMTPD_STAND_ALONE(state) == 0
 	&& !xclient_allowed
 	&& anvil_clnt
-	&& var_smtpd_cmail_limit > 0
 	&& !namadr_list_match(hogger_list, state->name, state->addr)
 	&& anvil_clnt_mail(anvil_clnt, state->service, state->addr,
 			   &rate) == ANVIL_STAT_OK
+	&& var_smtpd_cmail_limit > 0
 	&& rate > var_smtpd_cmail_limit) {
 	state->error_mask |= MAIL_ERROR_POLICY;
 	smtpd_chat_reply(state, "450 4.7.1 Error: too much mail from %s",
@@ -2204,10 +2204,10 @@
     if (SMTPD_STAND_ALONE(state) == 0
 	&& !xclient_allowed
 	&& anvil_clnt
-	&& var_smtpd_crcpt_limit > 0
 	&& !namadr_list_match(hogger_list, state->name, state->addr)
 	&& anvil_clnt_rcpt(anvil_clnt, state->service, state->addr,
 			   &rate) == ANVIL_STAT_OK
+	&& var_smtpd_crcpt_limit > 0
 	&& rate > var_smtpd_crcpt_limit) {
 	state->error_mask |= MAIL_ERROR_POLICY;
 	msg_warn("Recipient address rate limit exceeded: %d from %s for service %s",
@@ -3555,8 +3555,7 @@
      * of client address information in connect and disconnect events. For
      * now we exclude xclient authorized hosts from event count/rate control.
      */
-    if (var_smtpd_cntls_limit > 0
-	&& state->tls_context
+    if (state->tls_context
 	&& state->tls_context->session_reused == 0
 	&& SMTPD_STAND_ALONE(state) == 0
 	&& !xclient_allowed
@@ -3564,6 +3563,7 @@
 	&& !namadr_list_match(hogger_list, state->name, state->addr)
 	&& anvil_clnt_newtls(anvil_clnt, state->service, state->addr,
 			     &rate) == ANVIL_STAT_OK
+	&& var_smtpd_cntls_limit > 0
 	&& rate > var_smtpd_cntls_limit) {
 	state->error_mask |= MAIL_ERROR_POLICY;
 	msg_warn("New TLS session rate limit exceeded: %d from %s for service %s",
@@ -3644,13 +3644,13 @@
      * of client address information in connect and disconnect events. For
      * now we exclude xclient authorized hosts from event count/rate control.
      */
-    if (var_smtpd_cntls_limit > 0
-	&& SMTPD_STAND_ALONE(state) == 0
+    if (SMTPD_STAND_ALONE(state) == 0
 	&& !xclient_allowed
 	&& anvil_clnt
 	&& !namadr_list_match(hogger_list, state->name, state->addr)
 	&& anvil_clnt_newtls_stat(anvil_clnt, state->service, state->addr,
 				  &rate) == ANVIL_STAT_OK
+	&& var_smtpd_cntls_limit > 0
 	&& rate > var_smtpd_cntls_limit) {
 	state->error_mask |= MAIL_ERROR_POLICY;
 	msg_warn("Refusing STARTTLS request from %s for service %s",
@@ -3819,12 +3819,12 @@
 			 state->namaddr, state->service);
 		break;
 	    }
-	    if (var_smtpd_cntls_limit > 0
-		&& !xclient_allowed
+	    if (!xclient_allowed
 		&& anvil_clnt
 		&& !namadr_list_match(hogger_list, state->name, state->addr)
 		&& anvil_clnt_newtls_stat(anvil_clnt, state->service,
 				    state->addr, &tls_rate) == ANVIL_STAT_OK
+		&& var_smtpd_cntls_limit > 0
 		&& tls_rate > var_smtpd_cntls_limit) {
 		state->error_mask |= MAIL_ERROR_POLICY;
 		msg_warn("Refusing TLS service request from %s for service %s",
@@ -4375,9 +4375,11 @@
     /*
      * Connection rate management.
      */
+    /*
     if (var_smtpd_crate_limit || var_smtpd_cconn_limit
 	|| var_smtpd_cmail_limit || var_smtpd_crcpt_limit
 	|| var_smtpd_cntls_limit)
+    */
 	anvil_clnt = anvil_clnt_create();
 }
 
--- src/smtpd/smtpd_check.c.orig	Sat Jul  8 05:32:43 2006
+++ src/smtpd/smtpd_check.c	Sun Aug 27 02:10:31 2006
@@ -237,6 +237,7 @@
 #include <dsn_util.h>
 #include <conv_time.h>
 #include <xtext.h>
+#include <anvil_clnt.h>
 
 /* Application-specific. */
 
@@ -347,6 +348,11 @@
 static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *);
 
  /*
+  * rate control.
+  */
+extern ANVIL_CLNT *anvil_clnt;
+
+ /*
   * YASLM.
   */
 #define STR	vstring_str
@@ -3428,6 +3434,8 @@
     ARGV   *list;
     int     found;
     int     saved_recursion = state->recursion++;
+    int     rate_mail, rate_rcpt, rate_newtls;
+    int     anvil_stat = ANVIL_STAT_FAIL;
 
     if (msg_verbose)
 	msg_info(">>> START %s RESTRICTIONS <<<", reply_class);
@@ -3470,6 +3478,15 @@
 	}
 
 	/*
+	 * rate control.
+	 */
+	if(anvil_clnt)
+	    anvil_stat = anvil_clnt_lookup(anvil_clnt,
+				state->service, state->addr,
+				&state->conn_count, &state->conn_rate,
+				&rate_mail, &rate_rcpt, &rate_newtls);
+
+	/*
 	 * Generic restrictions.
 	 */
 	if (strcasecmp(name, PERMIT_ALL) == 0) {
@@ -3796,6 +3813,99 @@
 		status = reject_unverified_address(state, state->recipient,
 				     state->recipient, SMTPD_NAME_RECIPIENT,
 						   var_unv_rcpt_code);
+	}
+
+	/*
+	 * rate control.
+	 */
+	else if (strcasecmp(name, CONN_COUNT_LIMIT) == 0) {
+	    if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
+		msg_warn("restriction %s must be followed by number", CONN_COUNT_LIMIT);
+		longjmp(smtpd_check_buf,
+			smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+					   451, "4.3.5",
+					   "Server configuration error"));
+	    } else {
+		cpp += 1;
+		if(anvil_stat == ANVIL_STAT_OK
+		   && state->conn_count > atoi(*cpp)) {
+		    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+						421, "4.7.0",
+						"Connection concurrency limit exceeded");
+		}
+	    }
+	}
+	else if (strcasecmp(name, CONN_RATE_LIMIT) == 0) {
+	    if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
+		msg_warn("restriction %s must be followed by number", CONN_RATE_LIMIT);
+		longjmp(smtpd_check_buf,
+			smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+					   451, "4.3.5",
+					   "Server configuration error"));
+	    } else {
+		cpp += 1;
+		if(anvil_stat == ANVIL_STAT_OK
+		   && state->conn_rate > atoi(*cpp)) {
+		    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+						421, "4.7.0",
+						"Connection rate limit exceeded");
+		}
+	    }
+	}
+	else if (strcasecmp(name, MAIL_RATE_LIMIT) == 0) {
+	    if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
+		msg_warn("restriction %s must be followed by number", MAIL_RATE_LIMIT);
+		longjmp(smtpd_check_buf,
+			smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+					   451, "4.3.5",
+					   "Server configuration error"));
+	    } else {
+		cpp += 1;
+		if(anvil_stat == ANVIL_STAT_OK
+		   && rate_mail > atoi(*cpp)) {
+		    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+						450, "4.7.1",
+						"Message delivery request rate limit exceeded");
+		}
+	    }
+	}
+	else if (strcasecmp(name, RCPT_RATE_LIMIT) == 0) {
+	    if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
+		msg_warn("restriction %s must be followed by number", RCPT_RATE_LIMIT);
+		longjmp(smtpd_check_buf,
+			smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+					   451, "4.3.5",
+					   "Server configuration error"));
+	    } else {
+		cpp += 1;
+		if(anvil_stat == ANVIL_STAT_OK
+		   && rate_rcpt > atoi(*cpp)) {
+		    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+						450, "4.7.1",
+						"Recipient address rate limit exceeded");
+		}
+	    }
+	}
+	else if (strcasecmp(name, NTLS_RATE_LIMIT) == 0) {
+	    if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
+		msg_warn("restriction %s must be followed by number", NTLS_RATE_LIMIT);
+		longjmp(smtpd_check_buf,
+			smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
+					   451, "4.3.5",
+					   "Server configuration error"));
+	    }
+#ifdef USE_TLS
+	    else {
+		cpp += 1;
+		if(state->tls_context
+		   && anvil_stat == ANVIL_STAT_OK
+		   && rate_newtls > atoi(*cpp)) {
+		    status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+						450, "4.7.1",
+						"New TLS session rate limit exceeded");
+		}
+	    }
+#endif
 	}
 
 	/*
