X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/46a36afae41f63de654269c8a0b7cf5852a85a14..4687a69c269ee3f2a7f0625e0147a503fd9d3d0b:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 94061f97d..5c9e64021 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2022 */ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -49,6 +49,8 @@ optimize out the tail recursion and so not make them too expensive. */ static void * function_store_malloc(PCRE2_SIZE size, void * tag) { +if (size > INT_MAX) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request"); return store_malloc((int)size); } @@ -63,12 +65,15 @@ if (block) store_free(block); static void * function_store_get(PCRE2_SIZE size, void * tag) { +if (size > INT_MAX) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request"); return store_get((int)size, GET_UNTAINTED); /* loses track of taint */ } static void function_store_nullfree(void * block, void * tag) { +/* We cannot free memory allocated using store_get() */ } @@ -847,7 +852,7 @@ exit(EXIT_FAILURE); /* fail if a length is too long */ static inline void -exim_len_fail_toolong(int itemlen, int maxlen, const char *description) +exim_len_fail_toolong(int itemlen, int maxlen, const char * description) { if (itemlen <= maxlen) return; @@ -858,8 +863,10 @@ exit(EXIT_FAILURE); /* only pass through the string item back to the caller if it's short enough */ static inline const uschar * -exim_str_fail_toolong(const uschar *item, int maxlen, const char *description) +exim_str_fail_toolong(const uschar * item, int maxlen, const char * description) { +if (!item) + exim_fail("exim: bad item for: %s\n", description); exim_len_fail_toolong(Ustrlen(item), maxlen, description); return item; } @@ -884,10 +891,10 @@ log_write(0, LOG_MAIN|LOG_PANIC, struct stat buf; if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf))) -{ + { if (buf.st_uid == owner && buf.st_gid == group) return 0; log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name); -} + } else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno)); #endif @@ -896,6 +903,18 @@ return -1; } +/* Bump the index for argv, checking for overflow, +and return the argument. */ + +static const uschar * +next_argv(const uschar ** argv, int * pi, int argc, const uschar * where) +{ +int i = *pi; +if (++i >= argc) exim_fail("exim: bad item for: %s\n", where); +return argv[*pi = i]; +} + + /************************************************* * Extract port from host address * *************************************************/ @@ -1026,47 +1045,53 @@ gstring * g = NULL; DEBUG(D_any) {} else g = show_db_version(g); g = string_cat(g, US"Support for:"); +#ifdef WITH_CONTENT_SCAN + g = string_cat(g, US" Content_Scanning"); +#endif #ifdef SUPPORT_CRYPTEQ g = string_cat(g, US" crypteq"); #endif +#ifdef EXPAND_DLFUNC + g = string_cat(g, US" Expand_dlfunc"); +#endif #if HAVE_ICONV g = string_cat(g, US" iconv()"); #endif #if HAVE_IPV6 g = string_cat(g, US" IPv6"); #endif -#ifdef HAVE_SETCLASSRESOURCES - g = string_cat(g, US" use_setclassresources"); -#endif #ifdef SUPPORT_PAM g = string_cat(g, US" PAM"); #endif #ifdef EXIM_PERL g = string_cat(g, US" Perl"); #endif -#ifdef EXPAND_DLFUNC - g = string_cat(g, US" Expand_dlfunc"); -#endif -#ifdef USE_TCP_WRAPPERS - g = string_cat(g, US" TCPwrappers"); -#endif #ifdef USE_GNUTLS g = string_cat(g, US" GnuTLS"); #endif +#ifdef SUPPORT_MOVE_FROZEN_MESSAGES + g = string_cat(g, US" move_frozen_messages"); +#endif #ifdef USE_OPENSSL g = string_cat(g, US" OpenSSL"); #endif +#if defined(CYRUS_PWCHECK_SOCKET) + g = string_cat(g, US" pwcheck"); +#endif +#if defined(RADIUS_CONFIG_FILE) + g = string_cat(g, US" radius"); +#endif #ifndef DISABLE_TLS_RESUME g = string_cat(g, US" TLS_resume"); #endif #ifdef SUPPORT_TRANSLATE_IP_ADDRESS g = string_cat(g, US" translate_ip_address"); #endif -#ifdef SUPPORT_MOVE_FROZEN_MESSAGES - g = string_cat(g, US" move_frozen_messages"); +#ifdef USE_TCP_WRAPPERS + g = string_cat(g, US" TCPwrappers"); #endif -#ifdef WITH_CONTENT_SCAN - g = string_cat(g, US" Content_Scanning"); +#ifdef HAVE_SETCLASSRESOURCES + g = string_cat(g, US" use_setclassresources"); #endif #ifdef SUPPORT_DANE g = string_cat(g, US" DANE"); @@ -1080,6 +1105,9 @@ g = string_cat(g, US"Support for:"); #ifndef DISABLE_DNSSEC g = string_cat(g, US" DNSSEC"); #endif +#ifndef DISABLE_ESMTP_LIMITS + g = string_cat(g, US" ESMTP_Limits"); +#endif #ifndef DISABLE_EVENT g = string_cat(g, US" Event"); #endif @@ -1126,9 +1154,6 @@ g = string_cat(g, US"Support for:"); #ifdef EXPERIMENTAL_DSN_INFO g = string_cat(g, US" Experimental_DSN_info"); #endif -#ifdef EXPERIMENTAL_ESMTP_LIMITS - g = string_cat(g, US" Experimental_ESMTP_Limits"); -#endif #ifdef EXPERIMENTAL_QUEUEFILE g = string_cat(g, US" Experimental_QUEUEFILE"); #endif @@ -1359,17 +1384,15 @@ Argument: the local part Returns: the local part, quoted if necessary */ -uschar * -local_part_quote(uschar *lpart) +const uschar * +local_part_quote(const uschar * lpart) { BOOL needs_quote = FALSE; gstring * g; -for (uschar * t = lpart; !needs_quote && *t != 0; t++) - { +for (const uschar * t = lpart; !needs_quote && *t; t++) needs_quote = !isalnum(*t) && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL && (*t != '.' || t == lpart || t[1] == 0); - } if (!needs_quote) return lpart; @@ -1377,8 +1400,8 @@ g = string_catn(NULL, US"\"", 1); for (;;) { - uschar *nq = US Ustrpbrk(lpart, "\\\""); - if (nq == NULL) + uschar * nq = US Ustrpbrk(lpart, "\\\""); + if (!nq) { g = string_cat(g, lpart); break; @@ -1531,7 +1554,7 @@ Returns: DOES NOT RETURN */ static void -exim_usage(uschar *progname) +exim_usage(const uschar * progname) { /* Handle specific program invocation variants */ @@ -1681,8 +1704,10 @@ if (isupper(big_buffer[0])) if (macro_read_assignment(big_buffer)) printf("Defined macro '%s'\n", mlast->name); } +else if (Ustrncmp(big_buffer, "set,t ", 6) == 0) + printf("%s\n", acl_standalone_setvar(big_buffer+6, TRUE)); else if (Ustrncmp(big_buffer, "set ", 4) == 0) - printf("%s\n", acl_standalone_setvar(big_buffer+4)); + printf("%s\n", acl_standalone_setvar(big_buffer+4, FALSE)); else if ((s = expand_string(big_buffer))) printf("%s\n", CS s); else printf("Failed: %s\n", expand_string_message); @@ -1738,9 +1763,9 @@ Returns: EXIT_SUCCESS if terminated successfully */ int -main(int argc, char **cargv) +main(int argc, char ** cargv) { -uschar **argv = USS cargv; +const uschar ** argv = CUSS cargv; int arg_receive_timeout = -1; int arg_smtp_receive_timeout = -1; int arg_error_handling = error_handling; @@ -1789,20 +1814,20 @@ BOOL verify_address_mode = FALSE; BOOL verify_as_sender = FALSE; BOOL rcpt_verify_quota = FALSE; BOOL version_printed = FALSE; -uschar *alias_arg = NULL; -uschar *called_as = US""; -uschar *cmdline_syslog_name = NULL; -uschar *start_queue_run_id = NULL; -uschar *stop_queue_run_id = NULL; -uschar *expansion_test_message = NULL; -const uschar *ftest_domain = NULL; -const uschar *ftest_localpart = NULL; -const uschar *ftest_prefix = NULL; -const uschar *ftest_suffix = NULL; -uschar *log_oneline = NULL; -uschar *malware_test_file = NULL; -uschar *real_sender_address; -uschar *originator_home = US"/"; +const uschar * alias_arg = NULL; +const uschar * called_as = US""; +const uschar * cmdline_syslog_name = NULL; +const uschar * start_queue_run_id = NULL; +const uschar * stop_queue_run_id = NULL; +const uschar * expansion_test_message = NULL; +const uschar * ftest_domain = NULL; +const uschar * ftest_localpart = NULL; +const uschar * ftest_prefix = NULL; +const uschar * ftest_suffix = NULL; +uschar * log_oneline = NULL; +const uschar * malware_test_file = NULL; +const uschar * real_sender_address; +uschar * originator_home = US"/"; size_t sz; struct passwd *pw; @@ -2146,8 +2171,8 @@ on the second character (the one after '-'), to save some effort. */ for (i = 1; i < argc; i++) { BOOL badarg = FALSE; - uschar * arg = argv[i]; - uschar * argrest; + const uschar * arg = argv[i]; + const uschar * argrest; uschar switchchar; /* An argument not starting with '-' is the start of a recipients list; @@ -2341,7 +2366,7 @@ on the second character (the one after '-'), to save some effort. */ case 'I': if (Ustrlen(argrest) >= 1 && *argrest == ':') { - uschar *p = argrest+1; + const uschar * p = argrest+1; info_flag = CMDINFO_HELP; if (Ustrlen(p)) if (strcmpic(p, CUS"sieve") == 0) @@ -2607,14 +2632,11 @@ on the second character (the one after '-'), to save some effort. */ reset_point = store_mark(); while (Ufgets(big_buffer, big_buffer_size, trust_list)) { - uschar *start = big_buffer, *nl; - while (*start && isspace(*start)) - start++; - if (*start != '/') + uschar * start = big_buffer, * nl; + if (Uskip_whitespace(&start) != '/') continue; - nl = Ustrchr(start, '\n'); - if (nl) - *nl = 0; + if ((nl = Ustrchr(start, '\n'))) + *nl = '\0'; trusted_configs[nr_configs++] = string_copy(start); if (nr_configs == nelem(trusted_configs)) break; @@ -2668,12 +2690,12 @@ on the second character (the one after '-'), to save some effort. */ #else { int ptr = 0; - macro_item *m; + macro_item * m; uschar name[24]; - uschar *s = argrest; + const uschar * s = argrest; opt_D_used = TRUE; - while (isspace(*s)) s++; + Uskip_whitespace(&s); if (*s < 'A' || *s > 'Z') exim_fail("exim: macro name set by -D must start with " @@ -2686,11 +2708,10 @@ on the second character (the one after '-'), to save some effort. */ } name[ptr] = 0; if (ptr == 0) { badarg = TRUE; break; } - while (isspace(*s)) s++; - if (*s != 0) + if (Uskip_whitespace(&s)) { if (*s++ != '=') { badarg = TRUE; break; } - while (isspace(*s)) s++; + Uskip_whitespace(&s); } for (m = macros_user; m; m = m->next) @@ -2824,10 +2845,14 @@ on the second character (the one after '-'), to save some effort. */ if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f"); if (!*argrest) - *(sender_address = store_get(1, GET_UNTAINTED)) = '\0'; /* Ensure writeable memory */ + { + uschar * s = store_get(1, GET_UNTAINTED); /* Ensure writeable memory */ + *s = '\0'; + sender_address = s; + } else { - uschar * temp = argrest + Ustrlen(argrest) - 1; + const uschar * temp = argrest + Ustrlen(argrest) - 1; while (temp >= argrest && isspace(*temp)) temp--; if (temp >= argrest && *temp == '.') f_end_dot = TRUE; allow_domain_literals = TRUE; @@ -2992,7 +3017,7 @@ on the second character (the one after '-'), to save some effort. */ case 'K': smtp_peer_options |= OPTION_CHUNKING; break; -#ifdef EXPERIMENTAL_ESMTP_LIMITS +#ifndef DISABLE_ESMTP_LIMITS /* -MCL: peer used LIMITS RCPTMAX and/or RCPTDOMAINMAX */ case 'L': if (++i < argc) continue_limit_mail = Uatoi(argv[i]); else badarg = TRUE; @@ -3145,7 +3170,8 @@ on the second character (the one after '-'), to save some effort. */ { msg_action = MSG_SETQUEUE; queue_name_dest = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"), + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_DRIVERNAME_MAX, "-MG"), GET_TAINTED); } else if (Ustrcmp(argrest, "mad") == 0) msg_action = MSG_MARK_ALL_DELIVERED; @@ -3266,7 +3292,7 @@ on the second character (the one after '-'), to save some effort. */ /* -oB: Set a connection message max value for remote deliveries */ case 'B': { - uschar * p = argrest; + const uschar * p = argrest; if (!*p) if (i+1 < argc && isdigit((argv[i+1][0]))) p = argv[++i]; @@ -3357,36 +3383,36 @@ on the second character (the one after '-'), to save some effort. */ if (Ustrcmp(argrest, "a") == 0) sender_host_address = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_IPADDR_MAX, "-oMa"), GET_TAINTED); /* -oMaa: Set authenticator name */ else if (Ustrcmp(argrest, "aa") == 0) sender_host_authenticated = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_DRIVERNAME_MAX, "-oMaa"), GET_TAINTED); /* -oMas: setting authenticated sender */ else if (Ustrcmp(argrest, "as") == 0) authenticated_sender = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_EMAILADDR_MAX, "-oMas"), GET_TAINTED); /* -oMai: setting authenticated id */ else if (Ustrcmp(argrest, "ai") == 0) authenticated_id = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMai"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_EMAILADDR_MAX, "-oMai"), GET_TAINTED); /* -oMi: Set incoming interface address */ else if (Ustrcmp(argrest, "i") == 0) interface_address = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"), - GET_TAINTED); + exim_str_fail_toolong(next_argv(argv, &i, argc, arg), + EXIM_IPADDR_MAX, "-oMi"), GET_TAINTED); /* -oMm: Message reference */ @@ -3396,7 +3422,7 @@ on the second character (the one after '-'), to save some effort. */ exim_fail("-oMm must be a valid message ID\n"); if (!f.trusted_config) exim_fail("-oMm must be called by a trusted user/config\n"); - message_reference = argv[++i]; + message_reference = next_argv(argv, &i, argc, arg); } /* -oMr: Received protocol */ @@ -3406,26 +3432,32 @@ on the second character (the one after '-'), to save some effort. */ if (received_protocol) exim_fail("received_protocol is set already\n"); else - received_protocol = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"), - GET_TAINTED); + if (++i >= argc) badarg = TRUE; + else + received_protocol = string_copy_taint( + exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-oMr"), + GET_TAINTED); /* -oMs: Set sender host name */ else if (Ustrcmp(argrest, "s") == 0) - sender_host_name = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"), - GET_TAINTED); + if (++i >= argc) badarg = TRUE; + else + sender_host_name = string_copy_taint( + exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-oMs"), + GET_TAINTED); /* -oMt: Set sender ident */ else if (Ustrcmp(argrest, "t") == 0) - { - sender_ident_set = TRUE; - sender_ident = string_copy_taint( - exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"), - GET_TAINTED); - } + if (++i >= argc) badarg = TRUE; + else + { + sender_ident_set = TRUE; + sender_ident = string_copy_taint( + exim_str_fail_toolong(argv[i], EXIM_IDENTUSER_MAX, "-oMt"), + GET_TAINTED); + } /* Else a bad argument */ @@ -3453,7 +3485,9 @@ on the second character (the one after '-'), to save some effort. */ exim_fail("exim: only uid=%d or uid=%d can use -oP and -oPX " "(uid=%d euid=%d | %d)\n", root_uid, exim_uid, getuid(), geteuid(), real_uid); - if (!*argrest) override_pid_file_path = argv[++i]; + if (!*argrest) + if (++i < argc) override_pid_file_path = argv[i]; + else badarg = TRUE; else if (Ustrcmp(argrest, "X") == 0) delete_pid_file(); else badarg = TRUE; break; @@ -3481,10 +3515,9 @@ on the second character (the one after '-'), to save some effort. */ /* Limits: Is there a real limit we want here? 1024 is very arbitrary. */ case 'X': - if (*argrest) badarg = TRUE; + if (*argrest || ++i >= argc) badarg = TRUE; else override_local_interfaces = string_copy_taint( - exim_str_fail_toolong(argv[++i], 1024, "-oX"), - GET_TAINTED); + exim_str_fail_toolong(argv[i], 1024, "-oX"), GET_TAINTED); break; /* -oY: Override creation of daemon notifier socket */ @@ -3522,7 +3555,7 @@ on the second character (the one after '-'), to save some effort. */ which sets the host protocol and host name */ if (!*argrest) - if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; } + argrest = next_argv(argv, &i, argc, arg); if (*argrest) { @@ -3608,8 +3641,14 @@ on the second character (the one after '-'), to save some effort. */ else { - int intvl = readconf_readtime(*argrest ? argrest : argv[++i], 0, FALSE); - if (intvl <= 0) + int intvl; + const uschar * s; + + if (*argrest) s = argrest; + else if (++i < argc) { badarg = TRUE; break; } + else s = argv[i]; + + if ((intvl = readconf_readtime(s, 0, FALSE)) <= 0) exim_fail("exim: bad time value %s: abandoned\n", argv[i]); for (qrunner * qq = qrunners; qq; qq = qq->next) @@ -3652,7 +3691,7 @@ on the second character (the one after '-'), to save some effort. */ in all cases provided there are no further characters in this argument. */ - alloc_onetime_qrunner(); + if (!qrunners) alloc_onetime_qrunner(); qrunners->queue_2stage = f.queue_2stage; if (*argrest) for (int i = 0; i < nelem(rsopts); i++) @@ -3700,8 +3739,8 @@ on the second character (the one after '-'), to save some effort. */ tested. Otherwise variability of clock ticks etc. cause problems. */ case 'T': - if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0) - fudged_queue_times = string_copy_taint(argv[++i], GET_TAINTED); + if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0 && ++i < argc) + fudged_queue_times = string_copy_taint(argv[i], GET_TAINTED); else badarg = TRUE; break; @@ -4426,7 +4465,7 @@ if (bi_option) if (bi_command && *bi_command) { int i = 0; - uschar *argv[3]; + const uschar * argv[3]; argv[i++] = bi_command; /* nonexpanded option so assume untainted */ if (alias_arg) argv[i++] = alias_arg; argv[i++] = NULL; @@ -4472,7 +4511,8 @@ if (!f.admin_user) || queue_name_dest && prod_requires_admin || debugset && !f.running_in_test_harness ) - exim_fail("exim:%s permission denied\n", debugset ? " debugging" : ""); + exim_fail("exim:%s permission denied; not admin\n", + debugset ? " debugging" : ""); } /* If the real user is not root or the exim uid, the argument for passing @@ -4488,7 +4528,7 @@ if ( real_uid != root_uid && real_uid != exim_uid ) ) && !f.running_in_test_harness ) - exim_fail("exim: Permission denied\n"); + exim_fail("exim: Permission denied; not exim user or root\n"); /* If the caller is not trusted, certain arguments are ignored when running for real, but are permitted when checking things (-be, -bv, -bt, -bh, -bf, -bF). @@ -4754,7 +4794,7 @@ if (rcpt_verify_quota) exim_fail("exim: missing recipient for quota check\n"); else { - verify_quota(argv[recipients_arg]); + verify_quota(US argv[recipients_arg]); /*XXX we lose track of const here */ exim_exit(EXIT_SUCCESS); } @@ -5021,6 +5061,8 @@ for (i = 0;;) /* If a pattern for matching the gecos field was supplied, apply it and then expand the name string. */ + GET_OPTION("gecos_pattern"); + GET_OPTION("gecos_name"); if (gecos_pattern && gecos_name) { const pcre2_code *re; @@ -5066,6 +5108,7 @@ any setting of unknown_login overrides the actual name. */ if (!originator_login || f.running_in_test_harness) { + GET_OPTION("unknown_login"); if (unknown_login) { originator_login = expand_string(unknown_login); @@ -5297,6 +5340,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) @@ -5305,6 +5349,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); @@ -5363,17 +5408,18 @@ for hosts that want to play several parts at once. We need to ensure that it is set for host checking, and for receiving messages. */ smtp_active_hostname = primary_hostname; -if (raw_active_hostname != NULL) +GET_OPTION("smtp_active_hostname"); +if (raw_active_hostname) { - uschar *nah = expand_string(raw_active_hostname); - if (nah == NULL) + uschar * nah = expand_string(raw_active_hostname); + if (!nah) { if (!f.expand_string_forcedfail) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand \"%s\" " "(smtp_active_hostname): %s", raw_active_hostname, expand_string_message); } - else if (nah[0] != 0) smtp_active_hostname = nah; + else if (nah[0]) smtp_active_hostname = nah; } /* Handle host checking: this facility mocks up an incoming SMTP call from a @@ -5418,6 +5464,7 @@ if (host_checking) "**** This is not for real!\n\n", sender_host_address); + connection_id = getpid(); memset(sender_host_cache, 0, sizeof(sender_host_cache)); if (verify_check_host(&hosts_connection_nolog) == OK) { @@ -5606,6 +5653,7 @@ because a log line has already been written for all its failure exists (usually "connection refused: ") and writing another one is unnecessary clutter. */ +connection_id = getpid(); if (smtp_input) { smtp_in = stdin; @@ -5629,6 +5677,7 @@ if (smtp_input) else { + GET_OPTION("message_size_limit"); thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); if (expand_string_message) if (thismessage_size_limit == -1) @@ -5709,8 +5758,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; @@ -5721,14 +5770,18 @@ for (BOOL more = TRUE; more; ) the very end. The result of the ACL is ignored (as for other non-SMTP messages). It is run for its potential side effects. */ - if (smtp_batched_input && acl_not_smtp_start != NULL) - { - uschar *user_msg, *log_msg; - f.enable_dollar_recipients = TRUE; - (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, - &user_msg, &log_msg); - f.enable_dollar_recipients = FALSE; - } + if (smtp_batched_input) + { + GET_OPTION("acl_not_smtp_start"); + if (acl_not_smtp_start) + { + uschar * user_msg, * log_msg; + f.enable_dollar_recipients = TRUE; + (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, + &user_msg, &log_msg); + f.enable_dollar_recipients = FALSE; + } + } /* Now get the data for the message */ @@ -5757,9 +5810,11 @@ for (BOOL more = TRUE; more; ) else { - int rcount = 0; - int count = argc - recipients_arg; - uschar **list = argv + 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 */ @@ -5777,7 +5832,7 @@ for (BOOL more = TRUE; more; ) int start, end, domain; uschar * errmess; /* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short. - * We'll still want to cap it to something, just in case. */ + We'll still want to cap it to something, just in case. */ uschar * s = string_copy_taint( exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"), GET_TAINTED); @@ -5787,15 +5842,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"); @@ -5805,6 +5864,7 @@ for (BOOL more = TRUE; more; ) return moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; + } #ifdef SUPPORT_I18N { @@ -5829,6 +5889,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", @@ -5845,11 +5909,12 @@ 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; if (!finished) - while (*(++s) != 0 && (*s == ',' || isspace(*s))); + while (*++s && (*s == ',' || isspace(*s))); } } @@ -5870,9 +5935,10 @@ for (BOOL more = TRUE; more; ) ignored; rejecting here would just add complication, and it can just as well be done later. Allow $recipients to be visible in the ACL. */ + GET_OPTION("acl_not_smtp_start"); if (acl_not_smtp_start) { - uschar *user_msg, *log_msg; + uschar * user_msg, * log_msg; f.enable_dollar_recipients = TRUE; (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start, &user_msg, &log_msg); @@ -6112,6 +6178,7 @@ MORELOOP: deliver_localpart_data = deliver_domain_data = recipient_data = sender_data = NULL; acl_var_m = NULL; + lookup_value = NULL; /* Can be set by ACL */ store_reset(reset_point); }