Expand recipients_max
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 11 Feb 2024 23:32:34 +0000 (23:32 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 13 Feb 2024 18:32:04 +0000 (18:32 +0000)
19 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
src/src/exim.c
src/src/globals.c
src/src/globals.h
src/src/moan.c
src/src/readconf.c
src/src/receive.c
src/src/smtp_in.c
test/confs/0289
test/log/0289
test/log/4710
test/mail/0289.CALLER
test/mail/0289.userx [new file with mode: 0644]
test/mail/0289.usery [new file with mode: 0644]
test/scripts/0000-Basic/0289
test/scripts/4710-esmtp-limits/4710
test/stdout/4710

index 902f8e72f2e7f9748fae66977bbbec8e84f91d56..316860aae0df50a6a119e651111f055185a5093f 100644 (file)
@@ -17472,16 +17472,26 @@ or if the message was submitted locally (not using TCP/IP), and the &%-bnq%&
 option was not set.
 
 
-.option recipients_max main integer 50000
+.option recipients_max main integer&!! 50000
 .cindex "limit" "number of recipients"
 .cindex "recipient" "maximum number"
-If this option is set greater than zero, it specifies the maximum number of
+If the value resulting from expanding this option
+is set greater than zero, it specifies the maximum number of
 original recipients for any message. Additional recipients that are generated
 by aliasing or forwarding do not count. SMTP messages get a 452 response for
 all recipients over the limit; earlier recipients are delivered as normal.
 Non-SMTP messages with too many recipients are failed, and no deliveries are
 done.
 
+.new
+For SMTP message the expansion is done after the connection is
+accepted (but before any SMTP conversation) and may depend on
+the IP addresses and port numbers of the connection.
+&*Note*&: If an expansion is used for the option,
+care should be taken that a resonable value results for
+non-SMTP messages.
+.wen
+
 .cindex "RCPT" "maximum number of incoming"
 &*Note*&: The RFCs specify that an SMTP server should accept at least 100
 RCPT commands in a single message.
index ad385b9ecbc92a58037c1faaffae9b16736533fb..2439b313704875c9150bb3818257ab8c21a7d0b4 100644 (file)
@@ -16,6 +16,8 @@ Version 4.98
     timestamp but no extiry timestamp.  Code by Simon Arlott; testsuite
     additions by jgh.
 
+ 4. The recipients_max main option is now expanded.
+
 Version 4.97
 ------------
 
index 4d71176973c1c74f78438fa0202f435ac65cdb78..987f096ba122f8ab6597f30d569943aa211883d7 100644 (file)
@@ -475,7 +475,7 @@ receive_timeout                      time            0s            main
 received_header_text                 string*         +             main
 received_headers_max                 integer         30            main
 recipient_unqualified_hosts          host list       unset         main              4.00 replacing receiver_unqualified_hosts
-recipients_max                       integer         50000         main              1.60 default changed in 4.95 (was 0)
+recipients_max                       integer*        50000         main              1.60 default changed in 4.95 (was 0)
 recipients_max_reject                boolean         false         main              1.70
 redirect_router                      string          unset         routers           4.00
 remote_max_parallel                  integer         1             main
index 1f76f8f1435347ae9571af16551c9c30e1fa6391..10fc989632f124896212fa7966934091f4031efd 100644 (file)
@@ -5339,6 +5339,7 @@ if (expansion_test)
 
   else if (expansion_test_message)
     {
+    uschar * rme = expand_string(recipients_max);
     int save_stdin = dup(0);
     int fd = Uopen(expansion_test_message, O_RDONLY, 0);
     if (fd < 0)
@@ -5347,6 +5348,7 @@ if (expansion_test)
     (void) dup2(fd, 0);
     filter_test = FTEST_USER;      /* Fudge to make it look like filter test */
     message_ended = END_NOTENDED;
+    recipients_max_expanded = atoi(CCS rme);
     read_message_body(receive_msg(extract_recipients));
     message_linecount += body_linecount;
     (void)dup2(save_stdin, 0);
@@ -5753,8 +5755,8 @@ for (BOOL more = TRUE; more; )
     int rc;
     if ((rc = smtp_setup_msg()) > 0)
       {
-      if (real_sender_address != NULL &&
-          !receive_check_set_sender(sender_address))
+      if (   real_sender_address
+         && !receive_check_set_sender(sender_address))
         {
         sender_address = raw_sender = real_sender_address;
         sender_address_unrewritten = NULL;
@@ -5801,10 +5803,12 @@ for (BOOL more = TRUE; more; )
 
   else
     {
-    int rcount = 0;
-    int count = argc - recipients_arg;
+    uschar * rme = expand_string(recipients_max);
+    int rcount = 0, count = argc - recipients_arg;
     const uschar ** list = argv + recipients_arg;
 
+    recipients_max_expanded = atoi(CCS rme);
+
     /* These options cannot be changed dynamically for non-SMTP messages */
 
     f.active_local_sender_retain = local_sender_retain;
@@ -5831,15 +5835,19 @@ for (BOOL more = TRUE; more; )
       while (*s)
         {
         BOOL finished = FALSE;
-        uschar *recipient;
-        uschar *ss = parse_find_address_end(s, FALSE);
+        uschar * recipient;
+        uschar * ss = parse_find_address_end(s, FALSE);
 
         if (*ss == ',') *ss = 0; else finished = TRUE;
 
         /* Check max recipients - if -t was used, these aren't recipients */
 
-        if (recipients_max > 0 && ++rcount > recipients_max &&
-            !extract_recipients)
+        if (  recipients_max_expanded > 0 && ++rcount > recipients_max_expanded
+          && !extract_recipients)
+         {
+         DEBUG(D_all) debug_printf("excess reipients (max %d)\n",
+           recipients_max_expanded);
+
           if (error_handling == ERRORS_STDERR)
             {
             fprintf(stderr, "exim: too many recipients\n");
@@ -5849,6 +5857,7 @@ for (BOOL more = TRUE; more; )
             return
               moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)?
                 errors_sender_rc : EXIT_FAILURE;
+         }
 
 #ifdef SUPPORT_I18N
        {
@@ -5873,6 +5882,10 @@ for (BOOL more = TRUE; more; )
           }
 
         if (!recipient)
+         {
+         DEBUG(D_all) debug_printf("bad recipient address \"%s\": %s\n",
+           string_printing(list[i]), errmess);
+
           if (error_handling == ERRORS_STDERR)
             {
             fprintf(stderr, "exim: bad recipient address \"%s\": %s\n",
@@ -5889,6 +5902,7 @@ for (BOOL more = TRUE; more; )
               moan_to_sender(ERRMESS_BADARGADDRESS, &eblock, NULL, stdin, TRUE)?
                 errors_sender_rc : EXIT_FAILURE;
             }
+         }
 
         receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1);
         s = ss;
index c483ab1828b809a428054ba7013f231678eb2476..4af8668f0c03a42f8324f20fab83b7e5f1293b4e 100644 (file)
@@ -1322,7 +1322,8 @@ uschar *recipient_verify_failure = NULL;
 int     recipients_count       = 0;
 recipient_item  *recipients_list = NULL;
 int     recipients_list_max    = 0;
-int     recipients_max         = 50000;
+uschar *recipients_max         = US"50000";
+int     recipients_max_expanded= 0;
 const pcre2_code *regex_AUTH         = NULL;
 const pcre2_code *regex_check_dns_names = NULL;
 const pcre2_code *regex_From         = NULL;
index b5c3a520eadd08ab550e3fb5032de5acc0092c31..427590050c19b8cf46b304429762615d2e63d578 100644 (file)
@@ -895,7 +895,8 @@ extern uschar *recipient_data;         /* lookup data for recipients */
 extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */
 extern uschar *recipient_verify_failure; /* What went wrong */
 extern int     recipients_list_max;    /* Maximum number fitting in list */
-extern int     recipients_max;         /* Max permitted */
+extern uschar *recipients_max;         /* Max permitted */
+extern int     recipients_max_expanded;
 extern BOOL    recipients_max_reject;  /* If TRUE, reject whole message */
 extern const pcre2_code *regex_AUTH;         /* For recognizing AUTH settings */
 extern const pcre2_code  *regex_check_dns_names; /* For DNS name checking */
index c2e38d4f76e60ebb2ced6eaf9381592749b13ca0..a3c8e0aba4af20dc596e39f3ab71e02184b69d49 100644 (file)
@@ -561,7 +561,7 @@ switch(ident)
 
   case ERRMESS_TOOMANYRECIP:
   log_write(0, LOG_MAIN, "%s: too many recipients (max set to %d)", msg,
-    recipients_max);
+    recipients_max_expanded);
   break;
 
   case ERRMESS_LOCAL_SCAN:
index 8ee6e9fe071cd9008664f1054537ca89680ceca4..5b486d0b69dab40ddb2c8300933e2403ab0565ba 100644 (file)
@@ -293,7 +293,7 @@ static optionlist optionlist_config[] = {
   { "received_header_text",     opt_stringptr,   {&received_header_text} },
   { "received_headers_max",     opt_int,         {&received_headers_max} },
   { "recipient_unqualified_hosts", opt_stringptr, {&recipient_unqualified_hosts} },
-  { "recipients_max",           opt_int,         {&recipients_max} },
+  { "recipients_max",           opt_stringptr,   {&recipients_max} },
   { "recipients_max_reject",    opt_bool,        {&recipients_max_reject} },
 #ifdef LOOKUP_REDIS
   { "redis_servers",            opt_stringptr,   {&redis_servers} },
index ae4203e7fb77f52d73b6b23abdb7408e4a4c4736..990b9c22e8a239391d49a2f7d00d1504fc2b2337 100644 (file)
@@ -1204,6 +1204,8 @@ static void
 give_local_error(int errcode, uschar *text1, uschar *text2, int error_rc,
   FILE *f, header_line *hptr)
 {
+DEBUG(D_all) debug_printf("%s%s\n", text2, text1);
+
 if (error_handling == ERRORS_SENDER)
   {
   error_block eblock;
@@ -2622,12 +2624,12 @@ if (extract_recip)
     if ((h->type == htype_to || h->type == htype_cc || h->type == htype_bcc) &&
         (!contains_resent_headers || strncmpic(h->text, US"resent-", 7) == 0))
       {
-      uschar *s = Ustrchr(h->text, ':') + 1;
+      uschar * s = Ustrchr(h->text, ':') + 1;
       while (isspace(*s)) s++;
 
       f.parse_allow_group = TRUE;          /* Allow address group syntax */
 
-      while (*s != 0)
+      while (*s)
         {
         uschar *ss = parse_find_address_end(s, FALSE);
         uschar *recipient, *errmess, *pp;
@@ -2635,7 +2637,7 @@ if (extract_recip)
 
         /* Check on maximum */
 
-        if (recipients_max > 0 && ++rcount > recipients_max)
+        if (recipients_max_expanded > 0 && ++rcount > recipients_max_expanded)
           give_local_error(ERRMESS_TOOMANYRECIP, US"too many recipients",
             US"message rejected: ", error_rc, stdin, NULL);
           /* Does not return */
index a57c9821e94afd5ccaf3d2bc2491e833c93aed5c..1d4c232a501bd665136269808dda92cbfa3cd613 100644 (file)
@@ -1879,7 +1879,7 @@ while (done <= 0)
       if (recipients_max > 0 && recipients_count + 1 > recipients_max)
        /* The function moan_smtp_batch() does not return. */
        moan_smtp_batch(smtp_cmd_buffer, "%s too many recipients",
-         recipients_max_reject? "552": "452");
+         recipients_max_reject ? "552": "452");
 
       /* Apply SMTP rewrite, then extract address. Don't allow "<>" as a
       recipient address */
@@ -2540,6 +2540,11 @@ if (!f.sender_host_unknown)
   fl.helo_accept_junk = verify_check_host(&helo_accept_junk_hosts) == OK;
   }
 
+/* Expand recipients_max, if needed */
+ {
+  uschar * rme = expand_string(recipients_max);
+  recipients_max_expanded = atoi(CCS rme);
+ }
 /* For batch SMTP input we are now done. */
 
 if (smtp_batched_input) return TRUE;
@@ -4055,14 +4060,14 @@ while (done <= 0)
          }
 
 #ifndef DISABLE_ESMTP_LIMITS
-       if (  (smtp_mailcmd_max > 0 || recipients_max)
+       if (  (smtp_mailcmd_max > 0 || recipients_max_expanded > 0)
           && verify_check_host(&limits_advertise_hosts) == OK)
          {
          g = string_fmt_append(g, "%.3s-LIMITS", smtp_code);
          if (smtp_mailcmd_max > 0)
            g = string_fmt_append(g, " MAILMAX=%d", smtp_mailcmd_max);
-         if (recipients_max)
-           g = string_fmt_append(g, " RCPTMAX=%d", recipients_max);
+         if (recipients_max > 9)
+           g = string_fmt_append(g, " RCPTMAX=%d", recipients_max_expanded);
          g = string_catn(g, US"\r\n", 2);
          }
 #endif
@@ -4900,7 +4905,8 @@ while (done <= 0)
 
       /* Check maximum allowed */
 
-      if (rcpt_count+1 < 0 || rcpt_count > recipients_max && recipients_max > 0)
+      if (  rcpt_count+1 < 0
+         || rcpt_count > recipients_max_expanded && recipients_max_expanded > 0)
        {
        if (recipients_max_reject)
          {
index 44e40a528847a57e7f35a16f632d1e4da32acd11..a967996901a6fdf0acd96c607098e54efc2a16cf 100644 (file)
@@ -8,7 +8,11 @@ primary_hostname = myhost.test.ex
 # ----- Main settings -----
 
 acl_smtp_rcpt = accept
+.ifdef DYNAMIC_OPTION
+recipients_max = ${if def:sender_host_address {1}{2}}
+.else
 recipients_max = 1
+.endif
 
 
 # ------ Routers ------
index 15064bcdbc8a738050d66fa367a3cfe94e9ad7cc..e79c3e25ecacfc5ef15a4efa4c0ccae66756c947 100644 (file)
@@ -1,3 +1,10 @@
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= <> U=EXIMUSER P=local S=sss
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 => CALLER <CALLER@myhost.test.ex> R=r1 T=local_delivery
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 Completed
+1999-03-02 09:44:33 10HmaY-000000005vi-0000 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-000000005vi-0000 => userx <userx@myhost.test.ex> R=r1 T=local_delivery
+1999-03-02 09:44:33 10HmaY-000000005vi-0000 => usery <usery@myhost.test.ex> R=r1 T=local_delivery
+1999-03-02 09:44:33 10HmaY-000000005vi-0000 Completed
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 <= <> U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 => CALLER <CALLER@myhost.test.ex> R=r1 T=local_delivery
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 Completed
index 3937611b899101f642cfcc6dbf924d68d84d55f0..99934ebf591016d66ffcd22babbc0aa75b949d0d 100644 (file)
@@ -4,3 +4,5 @@
 1999-03-02 09:44:33 exim x.yz daemon started: pid=p1237, no queue runs, listening for SMTP on port PORT_D
 1999-03-02 09:44:33 exim x.yz daemon started: pid=p1238, no queue runs, listening for SMTP on port PORT_D
 1999-03-02 09:44:33 exim x.yz daemon started: pid=p1239, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 exim x.yz daemon started: pid=p1240, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 exim x.yz daemon started: pid=p1241, no queue runs, listening for SMTP on port PORT_D
index 2ba67d12b1c5a4f2d78b523638086ee0aabf2a37..3dc4f79baeaf60bf910c26054c5ce871f1f5e55d 100644 (file)
@@ -21,3 +21,24 @@ From: me
 Body
 .
 
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Received: from EXIMUSER by myhost.test.ex with local (Exim x.yz)
+       id 10HmaZ-000000005vi-0000
+       for CALLER@myhost.test.ex;
+       Tue, 2 Mar 1999 09:44:33 +0000
+Auto-Submitted: auto-replied
+From: Mail Delivery System <Mailer-Daemon@myhost.test.ex>
+To: CALLER@myhost.test.ex
+Subject: Mail failure - too many recipients
+Message-Id: <E10HmaZ-000000005vi-0000@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+A message that you sent contained more recipients than allowed on this
+system. It was not delivered to any recipients.
+
+------ This is a copy of your message, including all the headers. ------
+
+
+From: me
+.
+
diff --git a/test/mail/0289.userx b/test/mail/0289.userx
new file mode 100644 (file)
index 0000000..a789fc7
--- /dev/null
@@ -0,0 +1,10 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-000000005vi-0000;
+       Tue, 2 Mar 1999 09:44:33 +0000
+From: me@myhost.test.ex
+Message-Id: <E10HmaY-000000005vi-0000@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+
diff --git a/test/mail/0289.usery b/test/mail/0289.usery
new file mode 100644 (file)
index 0000000..a789fc7
--- /dev/null
@@ -0,0 +1,10 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-000000005vi-0000;
+       Tue, 2 Mar 1999 09:44:33 +0000
+From: me@myhost.test.ex
+Message-Id: <E10HmaY-000000005vi-0000@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+
index 2483b370632460d99522308ecb8a47007464f2d3..f768b80d0ad1ee588a01274e5087cf270f748a2f 100644 (file)
@@ -13,3 +13,14 @@ From: me
 Body
 .
 ****
+#
+# recipients_max should be expanded (here, for non-SMTP)
+exim -DDYNAMIC_OPTION -odi userx usery
+From: me
+.
+****
+1
+exim -odi -DDYNAMIC_OPTION userx usery userz
+From: me
+.
+****
index 875613cabd0ed6f949ad513a1a112a72eeb1fa01..a5b9a6a6cafcb707ce19b99d0b07196fa93cf9c8 100644 (file)
@@ -84,3 +84,26 @@ EHLO tester
 ??? 250
 ****
 killdaemon
+# recipients_max is expanded (at least for smtp)
+exim -DSERVER=server -DRCPT_MSG='${if eq {$sender_host_address}{HOSTIPV4}{4}{100}}' -bd -oX PORT_D
+****
+client HOSTIPV4 PORT_D
+??? 220
+EHLO tester
+??? 250-
+??? 250-SIZE
+??? 250-LIMITS MAILMAX=1000 RCPTMAX=4
+??? 250
+****
+killdaemon
+exim -DSERVER=server -DRCPT_MSG='${if eq {$sender_host_address}{HOSTIPV4}{4}{100}}' -bd -oX PORT_D
+****
+client 127.0.0.1 PORT_D
+??? 220
+EHLO tester
+??? 250-
+??? 250-SIZE
+??? 250-LIMITS MAILMAX=1000 RCPTMAX=100
+??? 250
+****
+killdaemon
index 701b4376c85573a36020fc9813feef483fe91437..7e031e24478979cdd20badc795111fa0d781ef5c 100644 (file)
@@ -85,3 +85,29 @@ Connecting to 127.0.0.1 port 1225 ... connected
 ??? 250
 <<< 250-8BITMIME
 End of script
+Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO tester
+??? 250-
+<<< 250-myhost.test.ex Hello tester [ip4.ip4.ip4.ip4]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-LIMITS MAILMAX=1000 RCPTMAX=4
+<<< 250-LIMITS MAILMAX=1000 RCPTMAX=4
+??? 250
+<<< 250-8BITMIME
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO tester
+??? 250-
+<<< 250-myhost.test.ex Hello tester [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-LIMITS MAILMAX=1000 RCPTMAX=100
+<<< 250-LIMITS MAILMAX=1000 RCPTMAX=100
+??? 250
+<<< 250-8BITMIME
+End of script