From 1c41c9ccd6545ff905a04b1004a11bf3cf82dc4f Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 6 Sep 2005 13:17:36 +0000 Subject: [PATCH] Support for verify=not_blind. --- doc/doc-txt/NewStuff | 14 +++++++- src/ACKNOWLEDGMENTS | 5 +-- src/src/acl.c | 39 +++++++++++++------- src/src/functions.h | 3 +- src/src/verify.c | 85 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 18 deletions(-) diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index b6b2d66da..151960efc 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.65 2005/08/23 08:50:07 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.66 2005/09/06 13:17:36 ph10 Exp $ New Features in Exim -------------------- @@ -108,6 +108,18 @@ PH/07 $smtp_command_argument is now set for all SMTP commands, not just the PH/08 The ${eval expansion now supports % as a "remainder" operator. +PH/09 There is a new ACL condition "verify = not_blind". It checks that there + are no blind (bcc) recipients in the message. Every envelope recipient + must appear either in a To: header line or in a Cc: header line for this + condition to be true. Local parts are checked case-sensitively; domains + are checked case-insensitively. If Resent-To: or Resent-Cc: header lines + exist, they are also checked. This condition can be used only in a DATA + or non-SMTP ACL. + + There are, of course, many legitimate messages that make use of blind + (bcc) recipients. This check should not be used on its own for blocking + messages. + Exim version 4.52 ----------------- diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index 9acc51b3c..6800012e7 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.32 2005/08/23 08:46:33 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.33 2005/09/06 13:17:36 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -20,7 +20,7 @@ relatively small patches. Philip Hazel Lists created: 20 November 2002 -Last updated: 23 August 2005 +Last updated: 06 September 2005 THE OLD LIST @@ -96,6 +96,7 @@ Andrew Doran Patch for NetBSD configuration files Michael Deutschmann Suggested patch for treating bind() failure like connect() Patch for $sender_data and $recipient_data Suggested patch for null address match lookup bug + Suggested patch for verify = not_blind Oliver Eikemeier Patch to skip Received: if expansion is empty Patch for "eqi" Nico Erfurth Fix for bug in ${readfile} diff --git a/src/src/acl.c b/src/src/acl.c index 4a73957ac..1be2e095c 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/acl.c,v 1.44 2005/08/22 14:01:37 ph10 Exp $ */ +/* $Cambridge: exim/src/src/acl.c,v 1.45 2005/09/06 13:17:36 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1409,18 +1409,29 @@ always). */ if (strcmpic(ss, US"header_syntax") == 0) { if (slash != NULL) goto NO_OPTIONS; - if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) - { - *log_msgptr = string_sprintf("cannot check header contents in ACL for %s " - "(only possible in ACL for DATA)", acl_wherenames[where]); - return ERROR; - } + if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL; rc = verify_check_headers(log_msgptr); if (rc != OK && smtp_return_error_details && *log_msgptr != NULL) *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr); return rc; } +/* Check that no recipient of this message is "blind", that is, every envelope +recipient must be mentioned in either To: or Cc:. */ + +if (strcmpic(ss, US"not_blind") == 0) + { + if (slash != NULL) goto NO_OPTIONS; + if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL; + rc = verify_check_notblind(); + if (rc != OK) + { + *log_msgptr = string_sprintf("bcc recipient detected"); + if (smtp_return_error_details) + *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr); + } + return rc; + } /* The remaining verification tests check recipient and sender addresses, either from the envelope or from the header. There are a number of @@ -1433,12 +1444,7 @@ sender and recipient. */ if (strcmpic(ss, US"header_sender") == 0) { - if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) - { - *log_msgptr = string_sprintf("cannot check header contents in ACL for %s " - "(only possible in ACL for DATA)", acl_wherenames[where]); - return ERROR; - } + if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL; verify_header_sender = TRUE; } @@ -1875,6 +1881,13 @@ NO_OPTIONS: *log_msgptr = string_sprintf("unexpected '/' found in \"%s\" " "(this verify item has no options)", arg); return ERROR; + +/* Calls in the wrong ACL come here */ + +WRONG_ACL: +*log_msgptr = string_sprintf("cannot check header contents in ACL for %s " + "(only possible in ACL for DATA)", acl_wherenames[where]); +return ERROR; } diff --git a/src/src/functions.h b/src/src/functions.h index 6d1f5cd8c..cccdbcaff 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/functions.h,v 1.19 2005/08/09 13:31:52 ph10 Exp $ */ +/* $Cambridge: exim/src/src/functions.h,v 1.20 2005/09/06 13:17:36 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -337,6 +337,7 @@ extern int verify_check_header_address(uschar **, uschar **, int, int, int, uschar *, uschar *, int, int *); extern int verify_check_headers(uschar **); extern int verify_check_host(uschar **); +extern int verify_check_notblind(void); extern int verify_check_this_host(uschar **, unsigned int *, uschar*, uschar *, uschar **); extern address_item *verify_checked_sender(uschar *); diff --git a/src/src/verify.c b/src/src/verify.c index c35571e6f..2614a23e0 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/verify.c,v 1.25 2005/08/22 10:49:04 ph10 Exp $ */ +/* $Cambridge: exim/src/src/verify.c,v 1.26 2005/09/06 13:17:36 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1451,6 +1451,89 @@ return OK; +/************************************************* +* Check for blind recipients * +*************************************************/ + +/* This function checks that every (envelope) recipient is mentioned in either +the To: or Cc: header lines, thus detecting blind carbon copies. + +There are two ways of scanning that could be used: either scan the header lines +and tick off the recipients, or scan the recipients and check the header lines. +The original proposed patch did the former, but I have chosen to do the latter, +because (a) it requires no memory and (b) will use fewer resources when there +are many addresses in To: and/or Cc: and only one or two envelope recipients. + +Arguments: none +Returns: OK if there are no blind recipients + FAIL if there is at least one blind recipient +*/ + +int +verify_check_notblind(void) +{ +int i; +for (i = 0; i < recipients_count; i++) + { + header_line *h; + BOOL found = FALSE; + uschar *address = recipients_list[i].address; + + for (h = header_list; !found && h != NULL; h = h->next) + { + uschar *colon, *s; + + if (h->type != htype_to && h->type != htype_cc) continue; + + colon = Ustrchr(h->text, ':'); + s = colon + 1; + while (isspace(*s)) s++; + + parse_allow_group = TRUE; /* Allow group syntax */ + + /* Loop for multiple addresses in the header */ + + while (*s != 0) + { + uschar *ss = parse_find_address_end(s, FALSE); + uschar *recipient,*errmess; + int terminator = *ss; + int start, end, domain; + + /* Temporarily terminate the string at this point, and extract the + operative address within. */ + + *ss = 0; + recipient = parse_extract_address(s,&errmess,&start,&end,&domain,FALSE); + *ss = terminator; + + /* If we found a valid recipient that has a domain, compare it with the + envelope recipient. Local parts are compared case-sensitively, domains + case-insensitively. By comparing from the start with length "domain", we + include the "@" at the end, which ensures that we are comparing the whole + local part of each address. */ + + if (recipient != NULL && domain != 0) + { + found = Ustrncmp(recipient, address, domain) == 0 && + strcmpic(recipient + domain, address + domain) == 0; + if (found) break; + } + + /* Advance to the next address */ + + s = ss + (terminator? 1:0); + while (isspace(*s)) s++; + } /* Next address */ + } /* Next header (if found is false) */ + + if (!found) return FAIL; + } /* Next recipient */ + +return OK; +} + + /************************************************* * Find if verified sender * -- 2.30.2