Support for verify=not_blind.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Tue, 6 Sep 2005 13:17:36 +0000 (13:17 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Tue, 6 Sep 2005 13:17:36 +0000 (13:17 +0000)
doc/doc-txt/NewStuff
src/ACKNOWLEDGMENTS
src/src/acl.c
src/src/functions.h
src/src/verify.c

index b6b2d66..151960e 100644 (file)
@@ -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
 -----------------
index 9acc51b..6800012 100644 (file)
@@ -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}
index 4a73957..1be2e09 100644 (file)
@@ -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;
 }
 
 
index 6d1f5cd..cccdbca 100644 (file)
@@ -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 *);
index c35571e..2614a23 100644 (file)
@@ -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               *