From cd19f9a79c20f9c0c9d650a8aa21d9cc54a66620 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 11 Feb 2024 23:32:34 +0000 Subject: [PATCH] Expand recipients_max --- doc/doc-docbook/spec.xfpt | 14 ++++++++++++-- doc/doc-txt/NewStuff | 2 ++ doc/doc-txt/OptionLists.txt | 2 +- src/src/exim.c | 30 +++++++++++++++++++++-------- src/src/globals.c | 3 ++- src/src/globals.h | 3 ++- src/src/moan.c | 2 +- src/src/readconf.c | 2 +- src/src/receive.c | 8 +++++--- src/src/smtp_in.c | 16 ++++++++++----- test/confs/0289 | 4 ++++ test/log/0289 | 7 +++++++ test/log/4710 | 2 ++ test/mail/0289.CALLER | 21 ++++++++++++++++++++ test/mail/0289.userx | 10 ++++++++++ test/mail/0289.usery | 10 ++++++++++ test/scripts/0000-Basic/0289 | 11 +++++++++++ test/scripts/4710-esmtp-limits/4710 | 23 ++++++++++++++++++++++ test/stdout/4710 | 26 +++++++++++++++++++++++++ 19 files changed, 173 insertions(+), 23 deletions(-) create mode 100644 test/mail/0289.userx create mode 100644 test/mail/0289.usery diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 902f8e72f..316860aae 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -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. diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index ad385b9ec..2439b3137 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -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 ------------ diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt index 4d7117697..987f096ba 100644 --- a/doc/doc-txt/OptionLists.txt +++ b/doc/doc-txt/OptionLists.txt @@ -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 diff --git a/src/src/exim.c b/src/src/exim.c index 1f76f8f14..10fc98963 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -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; diff --git a/src/src/globals.c b/src/src/globals.c index c483ab182..4af8668f0 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -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; diff --git a/src/src/globals.h b/src/src/globals.h index b5c3a520e..427590050 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -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 */ diff --git a/src/src/moan.c b/src/src/moan.c index c2e38d4f7..a3c8e0aba 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -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: diff --git a/src/src/readconf.c b/src/src/readconf.c index 8ee6e9fe0..5b486d0b6 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -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} }, diff --git a/src/src/receive.c b/src/src/receive.c index ae4203e7f..990b9c22e 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -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 */ diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index a57c9821e..1d4c232a5 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -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) { diff --git a/test/confs/0289 b/test/confs/0289 index 44e40a528..a96799690 100644 --- a/test/confs/0289 +++ b/test/confs/0289 @@ -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 ------ diff --git a/test/log/0289 b/test/log/0289 index 15064bcdb..e79c3e25e 100644 --- a/test/log/0289 +++ b/test/log/0289 @@ -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 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 R=r1 T=local_delivery +1999-03-02 09:44:33 10HmaY-000000005vi-0000 => usery 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 R=r1 T=local_delivery +1999-03-02 09:44:33 10HmaZ-000000005vi-0000 Completed diff --git a/test/log/4710 b/test/log/4710 index 3937611b8..99934ebf5 100644 --- a/test/log/4710 +++ b/test/log/4710 @@ -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 diff --git a/test/mail/0289.CALLER b/test/mail/0289.CALLER index 2ba67d12b..3dc4f79ba 100644 --- a/test/mail/0289.CALLER +++ b/test/mail/0289.CALLER @@ -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 +To: CALLER@myhost.test.ex +Subject: Mail failure - too many recipients +Message-Id: +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 index 000000000..a789fc76e --- /dev/null +++ b/test/mail/0289.userx @@ -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 ) + id 10HmaY-000000005vi-0000; + Tue, 2 Mar 1999 09:44:33 +0000 +From: me@myhost.test.ex +Message-Id: +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 index 000000000..a789fc76e --- /dev/null +++ b/test/mail/0289.usery @@ -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 ) + id 10HmaY-000000005vi-0000; + Tue, 2 Mar 1999 09:44:33 +0000 +From: me@myhost.test.ex +Message-Id: +Date: Tue, 2 Mar 1999 09:44:33 +0000 + + diff --git a/test/scripts/0000-Basic/0289 b/test/scripts/0000-Basic/0289 index 2483b3706..f768b80d0 100644 --- a/test/scripts/0000-Basic/0289 +++ b/test/scripts/0000-Basic/0289 @@ -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 +. +**** diff --git a/test/scripts/4710-esmtp-limits/4710 b/test/scripts/4710-esmtp-limits/4710 index 875613cab..a5b9a6a6c 100644 --- a/test/scripts/4710-esmtp-limits/4710 +++ b/test/scripts/4710-esmtp-limits/4710 @@ -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 diff --git a/test/stdout/4710 b/test/stdout/4710 index 701b4376c..7e031e244 100644 --- a/test/stdout/4710 +++ b/test/stdout/4710 @@ -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 -- 2.30.2