diff -urN milter-greylist-ORIG/acl.c milter-greylist/acl.c --- milter-greylist-ORIG/acl.c 2009-10-31 22:28:03.000000000 +0100 +++ milter-greylist/acl.c 2009-11-08 10:19:03.000000000 +0100 @@ -1845,6 +1845,14 @@ TAILQ_INSERT_TAIL(&acl_head, acl, a_list); gacl = acl_init_entry(); + if (acl_stage == AS_DATA && conf.c_first_dacl_line == INT_MAX) { + conf.c_first_dacl_line = conf_line - 1; + if (conf.c_debug) + mg_log(LOG_DEBUG, + "first dacl statement at line %d", + conf_line - 1); + } + if (conf.c_debug || conf.c_acldebug) { switch(acl_type) { case A_GREYLIST: @@ -1920,6 +1928,20 @@ if (acl->a_stage != stage) continue; + /* + * Skip dacl processing for lines beyond matched + * racl statement + */ + if (stage == AS_DATA && + acl->a_line > priv->priv_acl_line) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "skipping dacl commands beyond matched racl line %d", + priv->priv_acl_line); + acl = NULL; + break; + } + retval = 0; noretval = 0; found = -1; @@ -2004,7 +2026,7 @@ break; } - priv->priv_sr.sr_acl_line = acl->a_line; + priv->priv_acl_line = acl->a_line; priv->priv_sr.sr_delay = (ap.ap_delay != -1) ? ap.ap_delay : conf.c_delay; @@ -2114,15 +2136,17 @@ if (testmode) retval = EXF_WHITELIST; else if (stage == AS_DATA) - retval = EXF_WHITELIST | EXF_NOLOG; + retval = EXF_WHITELIST; else - retval = EXF_GREYLIST; + retval = EXF_WHITELIST; retval |= EXF_DEFAULT; priv->priv_sr.sr_delay = conf.c_delay; priv->priv_sr.sr_autowhite = conf.c_autowhite_validity; priv->priv_sr.sr_tarpit = conf.c_tarpit; priv->priv_sr.sr_tarpit_scope = conf.c_tarpit_scope; + + priv->priv_acl_line = INT_MAX; } if ((retval & EXF_NOLOG) == 0 && retval & EXF_WHITELIST) { diff -urN milter-greylist-ORIG/conf.c milter-greylist/conf.c --- milter-greylist-ORIG/conf.c 2009-09-09 14:19:17.000000000 +0200 +++ milter-greylist/conf.c 2009-11-08 10:19:03.000000000 +0100 @@ -447,6 +447,7 @@ c->c_forced = C_GLNONE; c->c_debug = 0; + c->c_first_dacl_line = INT_MAX; c->c_acldebug = 0; c->c_quiet = 0; c->c_noauth = 0; diff -urN milter-greylist-ORIG/conf.h milter-greylist/conf.h --- milter-greylist-ORIG/conf.h 2009-09-09 14:19:17.000000000 +0200 +++ milter-greylist/conf.h 2009-11-08 10:19:03.000000000 +0100 @@ -63,6 +63,7 @@ int c_forced; int c_debug; + int c_first_dacl_line; int c_acldebug; int c_quiet; int c_noauth; diff -urN milter-greylist-ORIG/dkimcheck.c milter-greylist/dkimcheck.c --- milter-greylist-ORIG/dkimcheck.c 2008-10-30 05:39:39.000000000 +0100 +++ milter-greylist/dkimcheck.c 2009-11-08 10:19:03.000000000 +0100 @@ -106,7 +106,7 @@ break; } - if (priv->priv_dkim != DKIM_STAT_OK) { + if (priv->priv_dkimstat != DKIM_STAT_OK) { (void)dkim_free(priv->priv_dkim); priv->priv_dkim = NULL; } diff -urN milter-greylist-ORIG/milter-greylist.c milter-greylist/milter-greylist.c --- milter-greylist-ORIG/milter-greylist.c 2009-11-06 04:52:25.000000000 +0100 +++ milter-greylist/milter-greylist.c 2009-11-08 10:19:03.000000000 +0100 @@ -483,6 +483,8 @@ free(priv->priv_buf); priv->priv_msgcount = 0; + priv->priv_acl_line = INT_MAX; + #ifdef USE_SPAMD priv->priv_spamd_flags = 0; #endif @@ -523,8 +525,10 @@ /* * Is the sender non-IP? */ - if (priv->priv_sr.sr_whitelist & EXF_NONIP) + if (priv->priv_sr.sr_whitelist & EXF_NONIP) { + priv->priv_acl_line = 0; return SMFIS_CONTINUE; + } /* * Is the user authenticated? @@ -537,6 +541,7 @@ priv->priv_sr.sr_elapsed = 0; priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_AUTH; + priv->priv_acl_line = 0; return SMFIS_CONTINUE; } @@ -553,6 +558,7 @@ priv->priv_sr.sr_elapsed = 0; priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_STARTTLS; + priv->priv_acl_line = 0; return SMFIS_CONTINUE; } @@ -574,6 +580,7 @@ priv->priv_sr.sr_elapsed = 0; priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_SPF; + priv->priv_acl_line = 0; return SMFIS_CONTINUE; } @@ -622,10 +629,10 @@ */ prop_clear(priv); #endif - - if ((priv->priv_sr.sr_whitelist & EXF_WHITELIST) && - (priv->priv_sr.sr_whitelist & - (EXF_NONIP | EXF_AUTH | EXF_STARTTLS | EXF_SPF))) + /* + * Skip if whitelisted in envfrom stage + */ + if (!priv->priv_acl_line) goto exit_accept; #ifdef USE_DRAC @@ -636,6 +643,7 @@ priv->priv_sr.sr_elapsed = 0; priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_DRAC; + priv->priv_acl_line = 0; goto exit_accept; } #endif @@ -653,7 +661,8 @@ "whitelisted by {greylist}"); priv->priv_sr.sr_elapsed = 0; priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_ACCESSDB; - + + priv->priv_acl_line = 0; goto exit_accept; } @@ -672,9 +681,23 @@ return SMFIS_TEMPFAIL; } + /* + * Immediately continue to dacl processing if any dacl statements + * occur before matching racl line + */ + if (conf.c_first_dacl_line < priv->priv_acl_line) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "dacl statement (line %d) before matched racl line %d; jump to dacl processing", + conf.c_first_dacl_line, priv->priv_acl_line); + + goto exit_accept; + } + if (priv->priv_sr.sr_whitelist & EXF_WHITELIST && priv->priv_sr.sr_tarpit <= 0) { priv->priv_sr.sr_elapsed = 0; + goto exit_accept; } @@ -725,6 +748,7 @@ case T_AUTOWHITE: /* autowhite listed */ priv->priv_sr.sr_elapsed = 0; priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_AUTO; + priv->priv_acl_line = 0; /* skip dacl */ goto exit_accept; break; case T_PENDING: /* greylisted */ @@ -784,6 +808,7 @@ add_recipient(priv, rcpt); if (priv->priv_sr.sr_whitelist & EXF_WHITELIST) priv->priv_last_whitelist = priv->priv_sr.sr_whitelist; + return SMFIS_CONTINUE; } @@ -821,7 +846,6 @@ exit(EX_OSERR); } - len = strlen(name) + strlen(sep) + strlen(value) + strlen(crlf); if ((h->h_line = malloc(len + 1)) == NULL) { mg_log(LOG_ERR, "malloc() failed: %s", strerror(errno)); exit(EX_OSERR); @@ -836,6 +860,18 @@ stat = SMFIS_CONTINUE; + /* + * No need to check headers for DKIM signature if there are + * no dacl statements before matching racl line + */ + if (conf.c_first_dacl_line >= priv->priv_acl_line) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "no dacl statements before matched racl line %d; skipping header inspection", + priv->priv_acl_line); + return SMFIS_CONTINUE; + } + #ifdef USE_DKIM if ((stat = dkimcheck_header(name, value, priv)) != SMFIS_CONTINUE) return stat; @@ -847,15 +883,28 @@ real_eoh(ctx) SMFICTX *ctx; { -#ifdef USE_DKIM struct mlfi_priv *priv; - sfsistat stat = SMFIS_CONTINUE; if ((priv = (struct mlfi_priv *) smfi_getpriv(ctx)) == NULL) { mg_log(LOG_ERR, "Internal error: smfi_getpriv() returns NULL"); return SMFIS_TEMPFAIL; } + /* + * No need to check headers for DKIM signature if there are + * no dacl statements before matching racl line + */ + if (conf.c_first_dacl_line >= priv->priv_acl_line) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "no dacl statements before matched racl line %d; skipping end-of-header", + priv->priv_acl_line); + return SMFIS_CONTINUE; + } + +#ifdef USE_DKIM + sfsistat stat = SMFIS_CONTINUE; + if ((stat = dkimcheck_eoh(priv)) != SMFIS_CONTINUE) return stat; #endif /* USE_DKIM */ @@ -882,6 +931,18 @@ stat = SMFIS_CONTINUE; + /* + * No need to scan the body if there are no dacl statements + * before matching racl line + */ + if (conf.c_first_dacl_line >= priv->priv_acl_line) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "no dacl statements before matched racl line %d; skipping body scan", + priv->priv_acl_line); + return SMFIS_CONTINUE; + } + #ifdef USE_DKIM if ((stat = dkimcheck_body(chunk, size, priv)) != SMFIS_CONTINUE) return stat; @@ -975,8 +1036,8 @@ struct smtp_reply rcpt_sr; struct rcpt *rcpt; time_t remaining; - int envrcpt_continue = 0; int accept = 1; + int save_acl_line; struct tuple_fields tuple; if ((priv = (struct mlfi_priv *) smfi_getpriv(ctx)) == NULL) { @@ -1010,24 +1071,34 @@ stat = SMFIS_CONTINUE; -#ifdef USE_DKIM - if ((stat = dkimcheck_eom(priv)) != SMFIS_CONTINUE) - return stat; -#endif - if (priv->priv_delayed_reject) { LIST_FOREACH(rcpt, &priv->priv_rcpt, r_list) log_and_report_greylisting(ctx, priv, rcpt->r_addr); return mg_stat(priv, SMFIS_TEMPFAIL); } - if (priv->priv_sr.sr_whitelist & EXF_WHITELIST && - priv->priv_sr.sr_whitelist & EXF_DEFAULT) - envrcpt_continue = 1; + /* + * If there are no dacl statements before matching racl line, + * the return code was handled in the rcpt stage; no need to + * do it here. Jump to logging and reporting + */ + if (conf.c_first_dacl_line >= priv->priv_acl_line) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "no dacl statements before matched racl line %d; skip to logging", + priv->priv_acl_line); + goto passed; + } + +#ifdef USE_DKIM + if ((stat = dkimcheck_eom(priv)) != SMFIS_CONTINUE) + return stat; +#endif /* * We save data obtained from RCPT and we will restore it afterward */ + save_acl_line = priv->priv_acl_line; memcpy(&rcpt_sr, &priv->priv_sr, sizeof(rcpt_sr)); smtp_reply_init(&priv->priv_sr); priv->priv_sr.sr_elapsed = priv->priv_max_elapsed; @@ -1036,6 +1107,31 @@ return SMFIS_TEMPFAIL; } + /* + * Only dacl lines up to racl match are evaluated; no match means + * we handle the racl result, followed by logging and reporting + */ + if (priv->priv_acl_line == INT_MAX) { + if (conf.c_debug) + mg_log(LOG_DEBUG, + "no dacl match before matching racl line; restoring racl results"); + + /* Restore the info collected from RCPT stage */ + smtp_reply_free(&priv->priv_sr); + memcpy(&priv->priv_sr, &rcpt_sr, sizeof(rcpt_sr)); + priv->priv_acl_line = save_acl_line; + } + + /* + * Handle dacl or delayed racl processing + */ + + if (priv->priv_sr.sr_whitelist & EXF_WHITELIST) { + priv->priv_sr.sr_elapsed = 0; + + goto passed; + } + if (priv->priv_sr.sr_whitelist & EXF_BLACKLIST) { char *aclstr; char addrstr[IPADDRSTRLEN]; @@ -1063,7 +1159,7 @@ return mg_stat(priv, stat_from_code(priv->priv_sr.sr_code)); } - if (priv->priv_sr.sr_whitelist & EXF_GREYLIST && envrcpt_continue) { + if (priv->priv_sr.sr_whitelist & EXF_GREYLIST) { /* * Multiple recipients for a single message. Here we check * each recipient individually for greylisting and autowhite @@ -1072,6 +1168,10 @@ priv->priv_sr.sr_whitelist &= ~EXF_NONE; LIST_FOREACH(rcpt, &priv->priv_rcpt, r_list) { + if (conf.c_debug) + mg_log(LOG_DEBUG, "data stage: evaluating greylist for recipient %s", + rcpt->r_addr); + tuple.sa = SA(&priv->priv_addr); tuple.salen = priv->priv_addrlen; tuple.from = priv->priv_from; @@ -1111,6 +1211,9 @@ } passed: + if (priv->priv_sr.sr_whitelist & EXF_WHITELIST) + priv->priv_last_whitelist = priv->priv_sr.sr_whitelist; + /* Add custom header from DATA stage ACL */ if (priv->priv_sr.sr_addheader) { char *hdrname; @@ -1130,10 +1233,6 @@ free(hdrname); } - /* Restore the info collected from RCPT stage */ - smtp_reply_free(&priv->priv_sr); - memcpy(&priv->priv_sr, &rcpt_sr, sizeof(rcpt_sr)); - if (priv->priv_max_elapsed == 0) { /* All recipients are whitelisted */ char *hdrstr = NULL; @@ -1205,10 +1304,19 @@ priv->priv_last_whitelist &= ~EXF_RCPT; } if (priv->priv_last_whitelist & EXF_AUTO) { + if (priv->priv_last_whitelist & EXF_DEFAULT) { + ADD_REASON(whystr, + "IP, sender and " + "recipient auto-whitelisted (default action)"); + priv->priv_last_whitelist &= ~EXF_AUTO; + priv->priv_last_whitelist &= ~EXF_DEFAULT; + } + else { ADD_REASON(whystr, "IP, sender and " "recipient auto-whitelisted"); priv->priv_last_whitelist &= ~EXF_AUTO; + } } if (priv->priv_last_whitelist & EXF_DNSRBL) { ADD_REASON(whystr, @@ -3075,9 +3183,9 @@ case 'A': { /* Line number for matching ACL */ char buf[16]; - if (priv->priv_sr.sr_acl_line) { + if (priv->priv_acl_line) { snprintf(buf, sizeof(buf), "%d", - priv->priv_sr.sr_acl_line); + priv->priv_acl_line); mystrncat(&outstr, buf, &outmaxlen); } else { mystrncat(&outstr, "(none)", &outmaxlen); @@ -3091,9 +3199,9 @@ snprintf(buf, sizeof(buf), "%s", priv->priv_sr.sr_acl_id); mystrncat(&outstr, buf, &outmaxlen); - } else if (priv->priv_sr.sr_acl_line) { + } else if (priv->priv_acl_line) { snprintf(buf, sizeof(buf), "%d", - priv->priv_sr.sr_acl_line); + priv->priv_acl_line); mystrncat(&outstr, buf, &outmaxlen); mystrncat(&outstr, "(none)", &outmaxlen); } diff -urN milter-greylist-ORIG/milter-greylist.h milter-greylist/milter-greylist.h --- milter-greylist-ORIG/milter-greylist.h 2009-11-01 03:03:33.000000000 +0100 +++ milter-greylist/milter-greylist.h 2009-11-08 10:19:03.000000000 +0100 @@ -155,7 +155,6 @@ int sr_nowhitelist; time_t sr_elapsed; time_t sr_remaining; - int sr_acl_line; char *sr_acl_id; time_t sr_delay; time_t sr_autowhite; @@ -209,6 +208,7 @@ char *priv_queueid; int priv_delayed_reject; struct smtp_reply priv_sr; + int priv_acl_line; time_t priv_max_elapsed; long long priv_last_whitelist; #if defined(USE_CURL) || defined(USE_LDAP)