X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/cd8cb71deb2d653228cc037cf91ecab980acdcd0..master:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 1f76f8f14..0eb221d43 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 - 2023 */ +/* Copyright (c) The Exim Maintainers 2020 - 2024 */ /* 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 */ @@ -33,6 +33,7 @@ Also a few functions that don't naturally fit elsewhere. */ #endif extern void init_lookup_list(void); +extern void init_misc_mod_list(void); @@ -237,7 +238,7 @@ va_end(ap); static void term_handler(int sig) { -exit(1); +exim_exit(EXIT_FAILURE); } @@ -274,22 +275,28 @@ static void #ifdef SA_SIGINFO segv_handler(int sig, siginfo_t * info, void * uctx) { -log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr); -# if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR) -switch (info->si_code) +if (!panic_coredump) { - case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break; - case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break; - case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break; - case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break; + log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr); + # if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR) + switch (info->si_code) + { + case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break; + case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break; + case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break; + case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break; + } + # endif } -# endif -if (US info->si_addr < US 4096) +if (panic_coredump) + log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (deliberate trap)"); +else if (US info->si_addr < US 4096) log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)"); else log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)"); if (process_info_len > 0) - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info); + log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%s: %.*s)", + process_purpose, process_info_len, process_info); stackdump(); signal(SIGSEGV, SIG_DFL); kill(getpid(), sig); @@ -997,38 +1004,204 @@ if (s) static gstring * show_db_version(gstring * g) { +g = string_cat(g, US"Hints DB:\n"); #ifdef DB_VERSION_STRING DEBUG(D_any) { - g = string_fmt_append(g, "Library version: BDB: Compile: %s\n", DB_VERSION_STRING); - g = string_fmt_append(g, " Runtime: %s\n", + g = string_fmt_append(g, " Library version: BDB: Compile: %s\n", DB_VERSION_STRING); + g = string_fmt_append(g, " Runtime: %s\n", db_version(NULL, NULL, NULL)); } else - g = string_fmt_append(g, "Berkeley DB: %s\n", DB_VERSION_STRING); + g = string_fmt_append(g, " Berkeley DB: %s\n", DB_VERSION_STRING); #elif defined(BTREEVERSION) && defined(HASHVERSION) # ifdef USE_DB - g = string_cat(g, US"Probably Berkeley DB version 1.8x (native mode)\n"); + g = string_cat(g, US" Probably Berkeley DB version 1.8x (native mode)\n"); # else - g = string_cat(g, US"Probably Berkeley DB version 1.8x (compatibility mode)\n"); + g = string_cat(g, US" Probably Berkeley DB version 1.8x (compatibility mode)\n"); # endif #elif defined(_DBM_RDONLY) || defined(dbm_dirfno) -g = string_cat(g, US"Probably ndbm\n"); +g = string_cat(g, US" Probably ndbm\n"); +#elif defined(USE_SQLITE) +g = string_cat(g, US" Using sqlite3\n"); #elif defined(USE_TDB) -g = string_cat(g, US"Using tdb\n"); +g = string_cat(g, US" Using tdb\n"); #else # ifdef USE_GDBM - g = string_cat(g, US"Probably GDBM (native mode)\n"); +g = string_cat(g, US" Probably GDBM (native mode)\n"); # else - g = string_cat(g, US"Probably GDBM (compatibility mode)\n"); +g = string_cat(g, US" Probably GDBM (compatibility mode)\n"); # endif #endif return g; } +static gstring * +lookup_show_supported(gstring * g) +{ +gstring * b = NULL, * d = NULL; + +#ifdef LOOKUP_LSEARCH +# if LOOKUP_LSEARCH!=2 + b = string_cat(b, US" lsearch wildlsearch nwildlsearch iplsearch"); +# else + d = string_cat(d, US" lsearch wildlsearch nwildlsearch iplsearch"); +# endif +#endif +#ifdef LOOKUP_CDB +# if LOOKUP_CDB!=2 + b = string_cat(b, US" cdb"); +# else + d = string_cat(d, US" cdb"); +# endif +#endif +#ifdef LOOKUP_DBM +# if LOOKUP_DBM!=2 + b = string_cat(b, US" dbm dbmjz dbmnz"); +# else + d = string_cat(d, US" dbm dbmjz dbmnz"); +# endif +#endif +#ifdef LOOKUP_DNSDB +# if LOOKUP_DNSDB!=2 + b = string_cat(b, US" dnsdb"); +# else + d = string_cat(d, US" dnsdb"); +# endif +#endif +#ifdef LOOKUP_DSEARCH +# if LOOKUP_DSEARCH!=2 + b = string_cat(b, US" dsearch"); +# else + d = string_cat(d, US" dsearch"); +# endif +#endif +#ifdef LOOKUP_IBASE +# if LOOKUP_IBASE!=2 + b = string_cat(b, US" ibase"); +# else + d = string_cat(d, US" ibase"); +# endif +#endif +#ifdef LOOKUP_JSON +# if LOOKUP_JSON!=2 + b = string_cat(b, US" json"); +# else + d = string_cat(d, US" json"); +# endif +#endif +#ifdef LOOKUP_LDAP +# if LOOKUP_LDAP!=2 + b = string_cat(b, US" ldap ldapdn ldapm"); +# else + d = string_cat(d, US" ldap ldapdn ldapm"); +# endif +#endif +#ifdef LOOKUP_LMDB +# if LOOKUP_LMDB!=2 + b = string_cat(b, US" lmdb"); +# else + d = string_cat(d, US" lmdb"); +# endif +#endif +#ifdef LOOKUP_MYSQL +# if LOOKUP_MYSQL!=2 + b = string_cat(b, US" mysql"); +# else + d = string_cat(d, US" mysql"); +# endif +#endif +#ifdef LOOKUP_NIS +# if LOOKUP_NIS!=2 + b = string_cat(b, US" nis nis0"); +# else + d = string_cat(d, US" nis nis0"); +# endif +#endif +#ifdef LOOKUP_NISPLUS +# if LOOKUP_NISPLUS!=2 + b = string_cat(b, US" nisplus"); +# else + d = string_cat(d, US" nisplus"); +# endif +#endif +#ifdef LOOKUP_ORACLE +# if LOOKUP_ORACLE!=2 + b = string_cat(b, US" oracle"); +# else + d = string_cat(d, US" oracle"); +# endif +#endif +#ifdef LOOKUP_PASSWD +# if LOOKUP_PASSWD!=2 + b = string_cat(b, US" passwd"); +# else + d = string_cat(d, US" passwd"); +# endif +#endif +#ifdef LOOKUP_PGSQL +# if LOOKUP_PGSQL!=2 + b = string_cat(b, US" pgsql"); +# else + d = string_cat(d, US" pgsql"); +# endif +#endif +#ifdef LOOKUP_REDIS +# if LOOKUP_REDIS!=2 + b = string_cat(b, US" redis"); +# else + d = string_cat(d, US" redis"); +# endif +#endif +#ifdef SUPPORT_SPF +# if SUPPORT_SPF!=2 + b = string_cat(b, US" spf"); +# else + d = string_cat(d, US" spf"); +# endif +#endif +#ifdef LOOKUP_SQLITE +# if LOOKUP_SQLITE!=2 + b = string_cat(b, US" sqlite"); +# else + d = string_cat(d, US" sqlite"); +# endif +#endif +#ifdef LOOKUP_TESTDB +# if LOOKUP_TESTDB!=2 + b = string_cat(b, US" testdb"); +# else + d = string_cat(d, US" testdb"); +# endif +#endif +#ifdef LOOKUP_WHOSON +# if LOOKUP_WHOSON!=2 + b = string_cat(b, US" whoson"); +# else + d = string_cat(d, US" whoson"); +# endif +#endif + +if (b) g = string_fmt_append(g, "Lookups (built-in):%Y\n", b); +if (d) g = string_fmt_append(g, "Lookups (dynamic): %Y\n", d); +return g; +} + + +static void +lookup_version_report_cb(uschar * name, uschar * ptr, void * ctx) +{ +const lookup_info * li = (lookup_info *)ptr; +gstring ** gp = ctx; + +if (li->version_report) + *gp = li->version_report(*gp); +} + + /* This function is called for -bV/--version and for -d to output the optional features of the current Exim binary. @@ -1048,6 +1221,12 @@ g = string_cat(g, US"Support for:"); #ifdef WITH_CONTENT_SCAN g = string_cat(g, US" Content_Scanning"); #endif +#ifndef DISABLE_EXIM_FILTER + g = string_cat(g, US" Exim_filter"); +#endif +#ifndef DISABLE_SIEVE_FILTER + g = string_cat(g, US" Sieve_filter"); +#endif #ifdef SUPPORT_CRYPTEQ g = string_cat(g, US" crypteq"); #endif @@ -1108,6 +1287,9 @@ g = string_cat(g, US"Support for:"); #ifndef DISABLE_ESMTP_LIMITS g = string_cat(g, US" ESMTP_Limits"); #endif +#ifndef DISABLE_WELLKNOWN + g = string_cat(g, US" ESMTP_Wellknown"); +#endif #ifndef DISABLE_EVENT g = string_cat(g, US" Event"); #endif @@ -1162,66 +1344,7 @@ g = string_cat(g, US"Support for:"); #endif g = string_cat(g, US"\n"); -g = string_cat(g, US"Lookups (built-in):"); -#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 - g = string_cat(g, US" lsearch wildlsearch nwildlsearch iplsearch"); -#endif -#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2 - g = string_cat(g, US" cdb"); -#endif -#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2 - g = string_cat(g, US" dbm dbmjz dbmnz"); -#endif -#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2 - g = string_cat(g, US" dnsdb"); -#endif -#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2 - g = string_cat(g, US" dsearch"); -#endif -#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 - g = string_cat(g, US" ibase"); -#endif -#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 - g = string_cat(g, US" json"); -#endif -#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 - g = string_cat(g, US" ldap ldapdn ldapm"); -#endif -#ifdef LOOKUP_LMDB - g = string_cat(g, US" lmdb"); -#endif -#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2 - g = string_cat(g, US" mysql"); -#endif -#if defined(LOOKUP_NIS) && LOOKUP_NIS!=2 - g = string_cat(g, US" nis nis0"); -#endif -#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2 - g = string_cat(g, US" nisplus"); -#endif -#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2 - g = string_cat(g, US" oracle"); -#endif -#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2 - g = string_cat(g, US" passwd"); -#endif -#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 - g = string_cat(g, US" pgsql"); -#endif -#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 - g = string_cat(g, US" redis"); -#endif -#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 - g = string_cat(g, US" sqlite"); -#endif -#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2 - g = string_cat(g, US" testdb"); -#endif -#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2 - g = string_cat(g, US" whoson"); -#endif -g = string_cat(g, US"\n"); - +g = lookup_show_supported(g); g = auth_show_supported(g); g = route_show_supported(g); g = transport_show_supported(g); @@ -1270,7 +1393,7 @@ DEBUG(D_any) gnu_get_libc_version()); #endif -g = show_db_version(g); + g = show_db_version(g); #ifndef DISABLE_TLS g = tls_version_report(g); @@ -1278,19 +1401,16 @@ g = show_db_version(g); #ifdef SUPPORT_I18N g = utf8_version_report(g); #endif -#ifdef SUPPORT_DMARC - g = dmarc_version_report(g); -#endif -#ifdef SUPPORT_SPF - g = spf_lib_version_report(g); -#endif -show_string(is_stdout, g); -g = NULL; +/*XXX do we need a "show misc-mods version-report" ? +Currently they are output in misc_mod_add() */ + + show_string(is_stdout, g); + g = NULL; -for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi) - if (authi->version_report) - g = (*authi->version_report)(g); + for (auth_info * ai = auths_available; ai; ai = (auth_info *)ai->drinfo.next) + if (ai->version_report) + g = (*ai->version_report)(g); /* PCRE_PRERELEASE is either defined and empty or a bare sequence of characters; unless it's an ancient version of PCRE in which case it @@ -1300,27 +1420,26 @@ for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi) #endif #define QUOTE(X) #X #define EXPAND_AND_QUOTE(X) QUOTE(X) - { - uschar buf[24]; - pcre2_config(PCRE2_CONFIG_VERSION, buf); - g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n" - " Runtime: %s\n", - PCRE2_MAJOR, PCRE2_MINOR, - EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "", - buf); - } + { + uschar buf[24]; + pcre2_config(PCRE2_CONFIG_VERSION, buf); + g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n" + " Runtime: %s\n", + PCRE2_MAJOR, PCRE2_MINOR, + EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "", + buf); + } #undef QUOTE #undef EXPAND_AND_QUOTE -show_string(is_stdout, g); -g = NULL; + show_string(is_stdout, g); + g = NULL; -init_lookup_list(); -for (int i = 0; i < lookup_list_count; i++) - if (lookup_list[i]->version_report) - g = lookup_list[i]->version_report(g); -show_string(is_stdout, g); -g = NULL; + init_lookup_list(); + tree_walk(lookups_tree, lookup_version_report_cb, &g); + show_string(is_stdout, g); + g = NULL; + init_misc_mod_list(); #ifdef WHITELIST_D_MACROS g = string_fmt_append(g, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS); @@ -1362,8 +1481,14 @@ switch(request) ); return; case CMDINFO_SIEVE: - for (const uschar ** pp = exim_sieve_extension_list; *pp; ++pp) - fprintf(stream, "%s\n", *pp); + { + const misc_module_info * mi; + typedef void (*fn_t)(FILE *); + if ((mi = misc_mod_find(US"sieve_filter", NULL))) + (((fn_t *) mi->functions)[SIEVE_EXTENSIONS]) (stream); + else + fprintf(stream, "Sieve filtering not available\n"); + } return; case CMDINFO_DSCP: dscp_list_to_stream(stream); @@ -1699,13 +1824,19 @@ len = Ustrlen(big_buffer); (void) macros_expand(0, &len, &dummy_macexp); +#ifdef LOOKUP_MODULE_DIR +//mod_load_check(big_buffer); +#endif + 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); @@ -2337,9 +2468,9 @@ on the second character (the one after '-'), to save some effort. */ /* -bh: Host checking - an IP address must follow. */ case 'h': - if (!*argrest || Ustrcmp(argrest, "c") == 0) + if ( (!*argrest || Ustrcmp(argrest, "c") == 0) + && ++i < argc) { - if (++i >= argc) { badarg = TRUE; break; } sender_host_address = string_copy_taint( exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"), GET_TAINTED); @@ -2347,7 +2478,8 @@ on the second character (the one after '-'), to save some effort. */ f.host_checking_callout = *argrest == 'c'; message_logs = FALSE; } - else badarg = TRUE; + else + badarg = TRUE; break; /* -bi: This option is used by sendmail to initialize *the* alias file, @@ -2630,14 +2762,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; @@ -2696,7 +2825,7 @@ on the second character (the one after '-'), to save some effort. */ 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 " @@ -2709,11 +2838,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) @@ -4094,6 +4222,7 @@ is equivalent to the ability to modify a setuid binary! This needs to happen before we read the main configuration. */ init_lookup_list(); +init_misc_mod_list(); /*XXX this excrescence could move to the testsuite standard config setup file */ #ifdef SUPPORT_I18N @@ -4382,9 +4511,16 @@ if (perl_start_option != 0) opt_perl_at_start = (perl_start_option > 0); if (opt_perl_at_start && opt_perl_startup != NULL) { - uschar *errstr; + uschar * errstr; + const misc_module_info * mi = misc_mod_find(US"perl", &errstr); + typedef uschar * (*fn_t)(uschar *); + + if (!mi) + exim_fail("exim: error finding perl module: %s\n", errstr); + DEBUG(D_any) debug_printf("Starting Perl interpreter\n"); - if ((errstr = init_perl(opt_perl_startup))) + + if ((errstr = (((fn_t *) mi->functions)[PERL_STARTUP]) (opt_perl_startup))) exim_fail("exim: error in perl_startup code: %s\n", errstr); opt_perl_started = TRUE; } @@ -4687,12 +4823,12 @@ if (malware_test_file) if ((result = malware_in_file(malware_test_file)) == FAIL) { printf("No malware found.\n"); - exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS); } if (result != OK) { printf("Malware lookup returned non-okay/fail: %d\n", result); - exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE); } if (malware_name) printf("Malware found: %s\n", malware_name); @@ -4701,7 +4837,7 @@ if (malware_test_file) #else printf("Malware scanning not enabled at compile time.\n"); #endif - exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE); } /* Handle a request to list the delivery queue */ @@ -4710,7 +4846,7 @@ if (list_queue) { set_process_info("listing the queue"); queue_list(list_queue_option, argv + recipients_arg, argc - recipients_arg); - exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS); } /* Handle a request to count the delivery queue */ @@ -4719,7 +4855,7 @@ if (count_queue) { set_process_info("counting the queue"); fprintf(stdout, "%u\n", queue_count()); - exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS); } /* Handle actions on specific messages, except for the force delivery and @@ -4758,7 +4894,7 @@ if (msg_action_arg > 0 && msg_action != MSG_DELIVER && msg_action != MSG_LOAD) else if (!queue_action(argv[msg_action_arg], msg_action, argv, argc, recipients_arg)) yield = EXIT_FAILURE; - exit(yield); + exim_exit(yield); } /* We used to set up here to skip reading the ACL section, on @@ -5063,6 +5199,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; @@ -5108,6 +5246,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); @@ -5158,7 +5297,7 @@ if (f.daemon_listen || f.inetd_wait_mode || is_multiple_qrun()) (void)gettimeofday(&t0, NULL); # endif if (!tls_dropprivs_validate_require_cipher(FALSE)) - exit(1); + exim_exit(EXIT_FAILURE); # ifdef MEASURE_TIMING report_time_since(&t0, US"validate_ciphers (delta)"); # endif @@ -5339,6 +5478,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 +5487,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); @@ -5365,8 +5506,12 @@ if (expansion_test) /* Expand command line items */ if (recipients_arg < argc) - while (recipients_arg < argc) - expansion_test_line(exim_str_fail_toolong(argv[recipients_arg++], EXIM_EMAILADDR_MAX, "recipient")); + { + config_filename = US"-be args"; + for (config_lineno = 1; recipients_arg < argc; config_lineno++) + expansion_test_line(exim_str_fail_toolong(argv[recipients_arg++], + EXIM_EMAILADDR_MAX, "-be arg")); + } /* Read stdin */ @@ -5380,7 +5525,9 @@ if (expansion_test) void *dlhandle = set_readline(&fn_readline, &fn_addhist); #endif - while (s = get_stdinput(fn_readline, fn_addhist)) + config_filename = US"-be stdin"; + for (config_lineno = 1; s = get_stdinput(fn_readline, fn_addhist); + config_lineno++) expansion_test_line(s); #ifdef USE_READLINE @@ -5405,17 +5552,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 @@ -5439,11 +5587,14 @@ if (host_checking) } /* In case the given address is a non-canonical IPv6 address, canonicalize - it. The code works for both IPv4 and IPv6, as it happens. */ + it. Use the compressed form for IPv6. */ size = host_aton(sender_host_address, x); sender_host_address = store_get(48, GET_UNTAINTED); /* large enough for full IPv6 */ - (void)host_nmtoa(size, x, -1, sender_host_address, ':'); + if (size == 1) + (void) host_nmtoa(size, x, -1, sender_host_address, ':'); + else + (void) ipv6_nmtoa(x, sender_host_address); /* Now set up for testing */ @@ -5460,7 +5611,7 @@ if (host_checking) "**** This is not for real!\n\n", sender_host_address); - connection_id = getpid(); + set_connection_id(); memset(sender_host_cache, 0, sizeof(sender_host_cache)); if (verify_check_host(&hosts_connection_nolog) == OK) { @@ -5484,9 +5635,6 @@ if (host_checking) return_path = sender_address = NULL; dnslist_domain = dnslist_matched = NULL; -#ifndef DISABLE_DKIM - dkim_cur_signer = NULL; -#endif acl_var_m = NULL; deliver_localpart_orig = NULL; deliver_domain_orig = NULL; @@ -5649,7 +5797,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(); +set_connection_id(); if (smtp_input) { smtp_in = stdin; @@ -5673,6 +5821,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) @@ -5753,8 +5902,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; @@ -5765,14 +5914,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 */ @@ -5801,10 +5954,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 +5986,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 +6008,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 +6033,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,11 +6053,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))); } } @@ -5914,9 +6079,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); @@ -6167,3 +6333,5 @@ return 0; /* To stop compiler warning */ /* End of exim.c */ +/* vi: aw ai sw=2 +*/