*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
*************************************************/
#ifdef _POSIX_MONOTONIC_CLOCK
-/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */
+# ifdef CLOCK_BOOTTIME
+# define EXIM_CLOCKTYPE CLOCK_BOOTTIME
+# else
+# define EXIM_CLOCKTYPE CLOCK_MONOTONIC
+# endif
+
+/* Amount EXIM_CLOCK is behind realtime, at startup. */
static struct timespec offset_ts;
static void
exim_clock_init(void)
{
struct timeval tv;
-if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return;
+if (clock_gettime(EXIM_CLOCKTYPE, &offset_ts) != 0) return;
(void)gettimeofday(&tv, NULL);
offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec;
offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec;
#endif
+void
+exim_gettime(struct timeval * tv)
+{
+#ifdef _POSIX_MONOTONIC_CLOCK
+struct timespec now_ts;
+
+if (clock_gettime(EXIM_CLOCKTYPE, &now_ts) == 0)
+ {
+ now_ts.tv_sec += offset_ts.tv_sec;
+ if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
+ {
+ now_ts.tv_sec++;
+ now_ts.tv_nsec -= 1000*1000*1000;
+ }
+ tv->tv_sec = now_ts.tv_sec;
+ tv->tv_usec = now_ts.tv_nsec / 1000;
+ }
+else
+#endif
+ (void)gettimeofday(tv, NULL);
+}
+
+
/* Exim uses a time + a pid to generate a unique identifier in two places: its
message IDs, and in file names for maildir deliveries. Because some OS now
re-use pids within the same second, sub-second times are now being used.
struct timeval now_tv;
long int now_true_usec;
-#ifdef _POSIX_MONOTONIC_CLOCK
-struct timespec now_ts;
-
-if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0)
- {
- now_ts.tv_sec += offset_ts.tv_sec;
- if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
- {
- now_ts.tv_sec++;
- now_ts.tv_nsec -= 1000*1000*1000;
- }
- now_tv.tv_sec = now_ts.tv_sec;
- now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution;
- now_tv.tv_usec = now_true_usec;
- }
-else
-#endif
- {
- (void)gettimeofday(&now_tv, NULL);
- now_true_usec = now_tv.tv_usec;
- now_tv.tv_usec = (now_true_usec/resolution) * resolution;
- }
+exim_gettime(&now_tv);
+now_true_usec = now_tv.tv_usec;
+now_tv.tv_usec = (now_true_usec/resolution) * resolution;
while (exim_tvcmp(&now_tv, tgt_tv) <= 0)
{
exit(EXIT_FAILURE);
}
+/* fail if a length is too long */
+static inline void
+exim_len_fail_toolong(int itemlen, int maxlen, const char *description)
+{
+if (itemlen <= maxlen)
+ return;
+fprintf(stderr, "exim: length limit exceeded (%d > %d) for: %s\n",
+ itemlen, maxlen, description);
+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_len_fail_toolong(Ustrlen(item), maxlen, description);
+return item;
+}
+
/* exim_chown_failure() called from exim_chown()/exim_fchown() on failure
of chown()/fchown(). See src/functions.h for more explanation */
int
uschar *parse_error = NULL;
uschar *address = parse_extract_address(s, &parse_error, &start, &end, &domain,
FALSE);
-if (address == NULL)
+if (!address)
{
fprintf(stdout, "syntax error: %s\n", parse_error);
*exit_value = 2;
static void
show_whats_supported(FILE * fp)
{
+rmark reset_point = store_mark();
+gstring * g;
DEBUG(D_any) {} else show_db_version(fp);
-fprintf(fp, "Support for:");
+g = string_cat(NULL, US"Support for:");
#ifdef SUPPORT_CRYPTEQ
- fprintf(fp, " crypteq");
+ g = string_cat(g, US" crypteq");
#endif
#if HAVE_ICONV
- fprintf(fp, " iconv()");
+ g = string_cat(g, US" iconv()");
#endif
#if HAVE_IPV6
- fprintf(fp, " IPv6");
+ g = string_cat(g, US" IPv6");
#endif
#ifdef HAVE_SETCLASSRESOURCES
- fprintf(fp, " use_setclassresources");
+ g = string_cat(g, US" use_setclassresources");
#endif
#ifdef SUPPORT_PAM
- fprintf(fp, " PAM");
+ g = string_cat(g, US" PAM");
#endif
#ifdef EXIM_PERL
- fprintf(fp, " Perl");
+ g = string_cat(g, US" Perl");
#endif
#ifdef EXPAND_DLFUNC
- fprintf(fp, " Expand_dlfunc");
+ g = string_cat(g, US" Expand_dlfunc");
#endif
#ifdef USE_TCP_WRAPPERS
- fprintf(fp, " TCPwrappers");
+ g = string_cat(g, US" TCPwrappers");
#endif
#ifdef USE_GNUTLS
- fprintf(fp, " GnuTLS");
+ g = string_cat(g, US" GnuTLS");
#endif
#ifdef USE_OPENSSL
- fprintf(fp, " OpenSSL");
+ g = string_cat(g, US" OpenSSL");
#endif
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
- fprintf(fp, " translate_ip_address");
+ g = string_cat(g, US" translate_ip_address");
#endif
#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
- fprintf(fp, " move_frozen_messages");
+ g = string_cat(g, US" move_frozen_messages");
#endif
#ifdef WITH_CONTENT_SCAN
- fprintf(fp, " Content_Scanning");
+ g = string_cat(g, US" Content_Scanning");
#endif
#ifdef SUPPORT_DANE
- fprintf(fp, " DANE");
+ g = string_cat(g, US" DANE");
#endif
#ifndef DISABLE_DKIM
- fprintf(fp, " DKIM");
+ g = string_cat(g, US" DKIM");
#endif
#ifndef DISABLE_DNSSEC
- fprintf(fp, " DNSSEC");
+ g = string_cat(g, US" DNSSEC");
#endif
#ifndef DISABLE_EVENT
- fprintf(fp, " Event");
+ g = string_cat(g, US" Event");
#endif
#ifdef SUPPORT_I18N
- fprintf(fp, " I18N");
+ g = string_cat(g, US" I18N");
#endif
#ifndef DISABLE_OCSP
- fprintf(fp, " OCSP");
+ g = string_cat(g, US" OCSP");
#endif
#ifndef DISABLE_PIPE_CONNECT
- fprintf(fp, " PIPE_CONNECT");
+ g = string_cat(g, US" PIPE_CONNECT");
#endif
#ifndef DISABLE_PRDR
- fprintf(fp, " PRDR");
+ g = string_cat(g, US" PRDR");
#endif
#ifdef SUPPORT_PROXY
- fprintf(fp, " PROXY");
+ g = string_cat(g, US" PROXY");
#endif
#ifdef SUPPORT_SOCKS
- fprintf(fp, " SOCKS");
+ g = string_cat(g, US" SOCKS");
#endif
#ifdef SUPPORT_SPF
- fprintf(fp, " SPF");
+ g = string_cat(g, US" SPF");
#endif
#ifdef SUPPORT_DMARC
- fprintf(fp, " DMARC");
+ g = string_cat(g, US" DMARC");
#endif
#ifdef TCP_FASTOPEN
tcp_init();
- if (f.tcp_fastopen_ok) fprintf(fp, " TCP_Fast_Open");
+ if (f.tcp_fastopen_ok) g = string_cat(g, US" TCP_Fast_Open");
#endif
#ifdef EXPERIMENTAL_ARC
- fprintf(fp, " Experimental_ARC");
+ g = string_cat(g, US" Experimental_ARC");
#endif
#ifdef EXPERIMENTAL_BRIGHTMAIL
- fprintf(fp, " Experimental_Brightmail");
+ g = string_cat(g, US" Experimental_Brightmail");
#endif
#ifdef EXPERIMENTAL_DCC
- fprintf(fp, " Experimental_DCC");
+ g = string_cat(g, US" Experimental_DCC");
#endif
#ifdef EXPERIMENTAL_DSN_INFO
- fprintf(fp, " Experimental_DSN_info");
+ g = string_cat(g, US" Experimental_DSN_info");
#endif
#ifdef EXPERIMENTAL_LMDB
- fprintf(fp, " Experimental_LMDB");
+ g = string_cat(g, US" Experimental_LMDB");
#endif
#ifdef EXPERIMENTAL_QUEUE_RAMP
- fprintf(fp, " Experimental_Queue_Ramp");
+ g = string_cat(g, US" Experimental_Queue_Ramp");
#endif
#ifdef EXPERIMENTAL_QUEUEFILE
- fprintf(fp, " Experimental_QUEUEFILE");
+ g = string_cat(g, US" Experimental_QUEUEFILE");
#endif
#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
- fprintf(fp, " Experimental_SRS");
+ g = string_cat(g, US" Experimental_SRS");
#endif
#ifdef EXPERIMENTAL_TLS_RESUME
- fprintf(fp, " Experimental_TLS_resume");
+ g = string_cat(g, US" Experimental_TLS_resume");
#endif
-fprintf(fp, "\n");
+g = string_cat(g, US"\n");
-fprintf(fp, "Lookups (built-in):");
+g = string_cat(g, US"Lookups (built-in):");
#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
- fprintf(fp, " lsearch wildlsearch nwildlsearch iplsearch");
+ g = string_cat(g, US" lsearch wildlsearch nwildlsearch iplsearch");
#endif
#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
- fprintf(fp, " cdb");
+ g = string_cat(g, US" cdb");
#endif
#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
- fprintf(fp, " dbm dbmjz dbmnz");
+ g = string_cat(g, US" dbm dbmjz dbmnz");
#endif
#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
- fprintf(fp, " dnsdb");
+ g = string_cat(g, US" dnsdb");
#endif
#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
- fprintf(fp, " dsearch");
+ g = string_cat(g, US" dsearch");
#endif
#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
- fprintf(fp, " ibase");
+ g = string_cat(g, US" ibase");
#endif
#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2
- fprintf(fp, " json");
+ g = string_cat(g, US" json");
#endif
#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
- fprintf(fp, " ldap ldapdn ldapm");
+ g = string_cat(g, US" ldap ldapdn ldapm");
#endif
#ifdef EXPERIMENTAL_LMDB
- fprintf(fp, " lmdb");
+ g = string_cat(g, US" lmdb");
#endif
#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
- fprintf(fp, " mysql");
+ g = string_cat(g, US" mysql");
#endif
#if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
- fprintf(fp, " nis nis0");
+ g = string_cat(g, US" nis nis0");
#endif
#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
- fprintf(fp, " nisplus");
+ g = string_cat(g, US" nisplus");
#endif
#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
- fprintf(fp, " oracle");
+ g = string_cat(g, US" oracle");
#endif
#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
- fprintf(fp, " passwd");
+ g = string_cat(g, US" passwd");
#endif
#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
- fprintf(fp, " pgsql");
+ g = string_cat(g, US" pgsql");
#endif
#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
- fprintf(fp, " redis");
+ g = string_cat(g, US" redis");
#endif
#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
- fprintf(fp, " sqlite");
+ g = string_cat(g, US" sqlite");
#endif
#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
- fprintf(fp, " testdb");
+ g = string_cat(g, US" testdb");
#endif
#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
- fprintf(fp, " whoson");
+ g = string_cat(g, US" whoson");
#endif
-fprintf(fp, "\n");
+g = string_cat(g, US"\n");
-auth_show_supported(fp);
-route_show_supported(fp);
-transport_show_supported(fp);
+g = auth_show_supported(g);
+g = route_show_supported(g);
+g = transport_show_supported(g);
#ifdef WITH_CONTENT_SCAN
-malware_show_supported(fp);
+g = malware_show_supported(g);
#endif
if (fixed_never_users[0] > 0)
{
int i;
- fprintf(fp, "Fixed never_users: ");
+ g = string_cat(g, US"Fixed never_users: ");
for (i = 1; i <= (int)fixed_never_users[0] - 1; i++)
- fprintf(fp, "%d:", (unsigned int)fixed_never_users[i]);
- fprintf(fp, "%d\n", (unsigned int)fixed_never_users[i]);
+ string_fmt_append(g, "%u:", (unsigned)fixed_never_users[i]);
+ g = string_fmt_append(g, "%u\n", (unsigned)fixed_never_users[i]);
}
-fprintf(fp, "Configure owner: %d:%d\n", config_uid, config_gid);
+g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid);
+fputs(CS string_from_gstring(g), fp);
fprintf(fp, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t));
#endif
} while (0);
+store_reset(reset_point);
}
*/
static void
-expansion_test_line(uschar * line)
+expansion_test_line(const uschar * line)
{
int len;
BOOL dummy_macexp;
+uschar * s;
Ustrncpy(big_buffer, line, big_buffer_size);
big_buffer[big_buffer_size-1] = '\0';
printf("Defined macro '%s'\n", mlast->name);
}
else
- if ((line = expand_string(big_buffer))) printf("%s\n", CS line);
+ if ((s = expand_string(big_buffer))) printf("%s\n", CS s);
else printf("Failed: %s\n", expand_string_message);
}
uschar *start_queue_run_id = NULL;
uschar *stop_queue_run_id = NULL;
uschar *expansion_test_message = NULL;
-uschar *ftest_domain = NULL;
-uschar *ftest_localpart = NULL;
-uschar *ftest_prefix = NULL;
-uschar *ftest_suffix = 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"/";
size_t sz;
-rmark reset_point;
struct passwd *pw;
struct stat statbuf;
if (f.running_in_test_harness)
debug_store = TRUE;
+/* Protect against abusive argv[0] */
+exim_str_fail_toolong(argv[0], PATH_MAX, "argv[0]");
+
/* The C standard says that the equivalent of setlocale(LC_ALL, "C") is obeyed
at the start of a program; however, it seems that some environments do not
follow this. A "strange" locale can affect the formatting of timestamps, so we
setlocale(LC_ALL, "C");
-/* Get the offset between CLOCK_MONOTONIC and wallclock */
+/* Get the offset between CLOCK_MONOTONIC/CLOCK_BOOTTIME and wallclock */
#ifdef _POSIX_MONOTONIC_CLOCK
exim_clock_init();
unprivileged = (real_uid != root_uid && original_euid != root_uid);
+/* For most of the args-parsing we need to use permanent pool memory */
+ {
+ int old_pool = store_pool;
+ store_pool = POOL_PERM;
+
/* Scan the program's arguments. Some can be dealt with right away; others are
simply recorded for checking and handling afterwards. Do a high-level switch
on the second character (the one after '-'), to save some effort. */
-for (i = 1; i < argc; i++)
+ for (i = 1; i < argc; i++)
{
BOOL badarg = FALSE;
- uschar *arg = argv[i];
- uschar *argrest;
+ uschar * arg = argv[i];
+ uschar * argrest;
int switchchar;
/* An argument not starting with '-' is the start of a recipients list;
/* sendmail uses -Ac and -Am to control which .cf file is used;
we ignore them. */
case 'A':
- if (*argrest == '\0') { badarg = TRUE; break; }
+ if (!*argrest) { badarg = TRUE; break; }
else
{
BOOL ignore = FALSE;
/* -bF: Run system filter test */
case 'F':
filter_test |= checking = FTEST_SYSTEM;
- if (*argrest) { badarg = TRUE; break; }
- if (++i < argc) filter_test_sfile = argv[i]; else
- exim_fail("exim: file name expected after %s\n", argv[i-1]);
+ if (*argrest) badarg = TRUE;
+ else if (++i < argc) filter_test_sfile = argv[i];
+ else exim_fail("exim: file name expected after %s\n", argv[i-1]);
break;
/* -bf: Run user filter test
{
if (++i >= argc)
exim_fail("exim: string expected after %s\n", arg);
- if (Ustrcmp(argrest, "d") == 0) ftest_domain = argv[i];
- else if (Ustrcmp(argrest, "l") == 0) ftest_localpart = argv[i];
- else if (Ustrcmp(argrest, "p") == 0) ftest_prefix = argv[i];
- else if (Ustrcmp(argrest, "s") == 0) ftest_suffix = argv[i];
+ if (Ustrcmp(argrest, "d") == 0) ftest_domain = exim_str_fail_toolong(argv[i], EXIM_DOMAINNAME_MAX, "-bfd");
+ else if (Ustrcmp(argrest, "l") == 0) ftest_localpart = exim_str_fail_toolong(argv[i], EXIM_LOCALPART_MAX, "-bfl");
+ else if (Ustrcmp(argrest, "p") == 0) ftest_prefix = exim_str_fail_toolong(argv[i], EXIM_LOCALPART_MAX, "-bfp");
+ else if (Ustrcmp(argrest, "s") == 0) ftest_suffix = exim_str_fail_toolong(argv[i], EXIM_LOCALPART_MAX, "-bfs");
else badarg = TRUE;
}
break;
if (!*argrest || Ustrcmp(argrest, "c") == 0)
{
if (++i >= argc) { badarg = TRUE; break; }
- sender_host_address = argv[i];
+ sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"), TRUE);
host_checking = checking = f.log_testing_mode = TRUE;
f.host_checking_callout = *argrest == 'c';
message_logs = FALSE;
concept of *the* alias file, but since Sun's YP make script calls
sendmail this way, some support must be provided. */
case 'i':
- if (!*++argrest) bi_option = TRUE;
+ if (!*argrest) bi_option = TRUE;
else badarg = TRUE;
break;
a change! Enforce a prefix check if required. */
case 'C':
- if (*argrest == 0)
- {
- if(++i < argc) argrest = argv[i]; else
- { badarg = TRUE; break; }
- }
+ if (!*argrest)
+ if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
if (Ustrcmp(config_main_filelist, argrest) != 0)
{
#ifdef ALT_CONFIG_PREFIX
const uschar *list = argrest;
uschar *filename;
while((filename = string_nextinlist(&list, &sep, big_buffer,
- big_buffer_size)) != NULL)
- {
- if ((Ustrlen(filename) < len ||
- Ustrncmp(filename, ALT_CONFIG_PREFIX, len) != 0 ||
- Ustrstr(filename, "/../") != NULL) &&
- (Ustrcmp(filename, "/dev/null") != 0 || real_uid != root_uid))
+ big_buffer_size)))
+ if ( ( Ustrlen(filename) < len
+ || Ustrncmp(filename, ALT_CONFIG_PREFIX, len) != 0
+ || Ustrstr(filename, "/../") != NULL
+ )
+ && (Ustrcmp(filename, "/dev/null") != 0 || real_uid != root_uid)
+ )
exim_fail("-C Permission denied\n");
- }
#endif
if (real_uid != root_uid)
{
else
{
/* Well, the trust list at least is up to scratch... */
- rmark reset_point = store_mark();
+ rmark reset_point;
uschar *trusted_configs[32];
int nr_configs = 0;
int i = 0;
+ int old_pool = store_pool;
+ store_pool = POOL_MAIN;
+ reset_point = store_mark();
while (Ufgets(big_buffer, big_buffer_size, trust_list))
{
uschar *start = big_buffer, *nl;
if (nl)
*nl = 0;
trusted_configs[nr_configs++] = string_copy(start);
- if (nr_configs == 32)
+ if (nr_configs == nelem(trusted_configs))
break;
}
fclose(trust_list);
const uschar *list = argrest;
uschar *filename;
while (f.trusted_config && (filename = string_nextinlist(&list,
- &sep, big_buffer, big_buffer_size)) != NULL)
+ &sep, big_buffer, big_buffer_size)))
{
for (i=0; i < nr_configs; i++)
if (Ustrcmp(filename, trusted_configs[i]) == 0)
else /* No valid prefixes found in trust_list file. */
f.trusted_config = FALSE;
store_reset(reset_point);
+ store_pool = old_pool;
}
}
else /* Could not open trust_list file. */
f.debug_daemon = TRUE;
argrest++;
}
- if (*argrest != 0)
+ if (*argrest)
decode_bits(&selector, 1, debug_notall, argrest,
debug_options, debug_options_count, US"debug", 0);
debug_selector = selector;
the -F or be in the next argument. */
case 'F':
- if (*argrest == 0)
- {
- if(++i < argc) argrest = argv[i]; else
- { badarg = TRUE; break; }
- }
- originator_name = argrest;
+ if (!*argrest)
+ if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
+ originator_name = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_HUMANNAME_MAX, "-F"), TRUE);
f.sender_name_forced = TRUE;
break;
{
int dummy_start, dummy_end;
uschar *errmess;
- if (*argrest == 0)
- {
- if (i+1 < argc) argrest = argv[++i]; else
- { badarg = TRUE; break; }
- }
- if (*argrest == 0)
+ if (!*argrest)
+ 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, FALSE)) = '\0'; /* Ensure writeable memory */
else
{
- uschar *temp = argrest + Ustrlen(argrest) - 1;
+ uschar * temp = argrest + Ustrlen(argrest) - 1;
while (temp >= argrest && isspace(*temp)) temp--;
if (temp >= argrest && *temp == '.') f_end_dot = TRUE;
allow_domain_literals = TRUE;
#ifdef SUPPORT_I18N
allow_utf8_domains = TRUE;
#endif
- sender_address = parse_extract_address(argrest, &errmess,
- &dummy_start, &dummy_end, &sender_address_domain, TRUE);
+ if (!(sender_address = parse_extract_address(argrest, &errmess,
+ &dummy_start, &dummy_end, &sender_address_domain, TRUE)))
+ exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess);
+
sender_address = string_copy_taint(sender_address, TRUE);
#ifdef SUPPORT_I18N
message_smtputf8 = string_is_utf8(sender_address);
#endif
allow_domain_literals = FALSE;
strip_trailing_dot = FALSE;
- if (!sender_address)
- exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess);
}
f.sender_address_forced = TRUE;
}
To put it in will require a change to the spool header file format. */
case 'h':
- if (*argrest == 0)
- {
- if(++i < argc) argrest = argv[i]; else
- { badarg = TRUE; break; }
- }
+ if (!*argrest)
+ if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
if (!isdigit(*argrest)) badarg = TRUE;
break;
not to be documented for sendmail but mailx (at least) uses it) */
case 'i':
- if (*argrest == 0) f.dot_ends = FALSE; else badarg = TRUE;
+ if (!*argrest) f.dot_ends = FALSE; else badarg = TRUE;
break;
syslog_processname in the config file, but needs to be an admin option. */
case 'L':
- if (*argrest == '\0')
- {
- if(++i < argc) argrest = argv[i]; else
- { badarg = TRUE; break; }
- }
+ if (!*argrest)
+ if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
if ((sz = Ustrlen(argrest)) > 32)
exim_fail("exim: the -L syslog name is too long: \"%s\"\n", argrest);
if (sz < 1)
exim_fail("exim: the -L syslog name is too short\n");
- cmdline_syslog_name = argrest;
+ cmdline_syslog_name = string_copy_taint(argrest, TRUE);
break;
case 'M':
if (msg_action_arg >= 0)
exim_fail("exim: incompatible arguments\n");
- continue_transport = argv[++i];
- continue_hostname = argv[++i];
- continue_host_address = argv[++i];
+ continue_transport = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-C internal transport"), TRUE);
+ continue_hostname = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-C internal hostname"), TRUE);
+ continue_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-C internal hostaddr"), TRUE);
continue_sequence = Uatoi(argv[++i]);
msg_action = MSG_DELIVER;
msg_action_arg = ++i;
/* -MCd: for debug, set a process-purpose string */
case 'd': if (++i < argc)
- process_purpose = string_copy_taint(argv[i], TRUE);
+ process_purpose = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCd"), TRUE);
else badarg = TRUE;
break;
/* -MCG: set the queue name, to a non-default value */
- case 'G': if (++i < argc) queue_name = string_copy(argv[i]);
+ case 'G': if (++i < argc) queue_name = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"), TRUE);
else badarg = TRUE;
break;
case 'S': smtp_peer_options |= OPTION_SIZE; break;
#ifndef DISABLE_TLS
+ /* -MCs: used with -MCt; SNI was sent */
+ /* -MCr: ditto, DANE */
+
+ case 'r':
+ case 's': if (++i < argc)
+ {
+ continue_proxy_sni = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-MCr/-MCs"), TRUE);
+ if (argrest[1] == 'r') continue_proxy_dane = TRUE;
+ }
+ else badarg = TRUE;
+ break;
+
/* -MCt: similar to -MCT below but the connection is still open
via a proxy process which handles the TLS context and coding.
Require three arguments for the proxied local address and port,
- and the TLS cipher. */
+ and the TLS cipher. */
- case 't': if (++i < argc) sending_ip_address = argv[i];
+ case 't': if (++i < argc)
+ sending_ip_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-MCt IP"), TRUE);
else badarg = TRUE;
- if (++i < argc) sending_port = (int)(Uatol(argv[i]));
+ if (++i < argc)
+ sending_port = (int)(Uatol(argv[i]));
else badarg = TRUE;
- if (++i < argc) continue_proxy_cipher = argv[i];
+ if (++i < argc)
+ continue_proxy_cipher = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_CIPHERNAME_MAX, "-MCt cipher"), TRUE);
else badarg = TRUE;
/*FALLTHROUGH*/
following options which are followed by a single message id, and which
act on that message. Some of them use the "recipient" addresses as well.
-Mar add recipient(s)
+ -MG move to a different queue
-Mmad mark all recipients delivered
-Mmd mark recipients(s) delivered
-Mes edit sender
-Mvl show log
*/
- else if (*argrest == 0)
+ else if (!*argrest)
{
msg_action = MSG_DELIVER;
forced_delivery = f.deliver_force_thaw = TRUE;
else if (Ustrcmp(argrest, "G") == 0)
{
msg_action = MSG_SETQUEUE;
- queue_name_dest = argv[++i];
+ queue_name_dest = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"), TRUE);
}
else if (Ustrcmp(argrest, "mad") == 0)
{
for sendmail it askes for "me too". Exim always does this. */
case 'm':
- if (*argrest != 0) badarg = TRUE;
+ if (*argrest) badarg = TRUE;
break;
their thing. It implies debugging at the D_v level. */
case 'N':
- if (*argrest == 0)
+ if (!*argrest)
{
f.dont_deliver = TRUE;
debug_selector |= D_v;
-O option=value and -Ooption=value. */
case 'O':
- if (*argrest == 0)
+ if (!*argrest)
if (++i >= argc)
exim_fail("exim: string expected after -O\n");
break;
/* -oMa: Set sender host address */
- if (Ustrcmp(argrest, "a") == 0) sender_host_address = argv[++i];
+ if (Ustrcmp(argrest, "a") == 0)
+ sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"), TRUE);
/* -oMaa: Set authenticator name */
else if (Ustrcmp(argrest, "aa") == 0)
- sender_host_authenticated = argv[++i];
+ sender_host_authenticated = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"), TRUE);
/* -oMas: setting authenticated sender */
else if (Ustrcmp(argrest, "as") == 0)
- authenticated_sender = string_copy_taint(argv[++i], TRUE);
+ authenticated_sender = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);
/* -oMai: setting authenticated id */
else if (Ustrcmp(argrest, "ai") == 0)
- authenticated_id = string_copy_taint(argv[++i], TRUE);
+ authenticated_id = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);
/* -oMi: Set incoming interface address */
- else if (Ustrcmp(argrest, "i") == 0) interface_address = argv[++i];
+ else if (Ustrcmp(argrest, "i") == 0)
+ interface_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"), TRUE);
/* -oMm: Message reference */
if (received_protocol)
exim_fail("received_protocol is set already\n");
else
- received_protocol = argv[++i];
+ received_protocol = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"), TRUE);
/* -oMs: Set sender host name */
else if (Ustrcmp(argrest, "s") == 0)
- sender_host_name = string_copy_taint(argv[++i], TRUE);
+ sender_host_name = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"), TRUE);
/* -oMt: Set sender ident */
else if (Ustrcmp(argrest, "t") == 0)
{
sender_ident_set = TRUE;
- sender_ident = argv[++i];
+ sender_ident = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"), TRUE);
}
/* Else a bad argument */
-oPX: delete pid file of daemon */
case 'P':
+ if (!f.running_in_test_harness && real_uid != root_uid && real_uid != exim_uid)
+ 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];
else if (Ustrcmp(argrest, "X") == 0) delete_pid_file();
else badarg = TRUE;
break;
/* -oX <list>: Override local_interfaces and/or default daemon ports */
+ /* Limits: Is there a real limit we want here? 1024 is very arbitrary. */
case 'X':
if (*argrest) badarg = TRUE;
- else override_local_interfaces = argv[++i];
+ else override_local_interfaces = string_copy_taint(exim_str_fail_toolong(argv[++i], 1024, "-oX"), TRUE);
break;
/* Unknown -o argument */
/* -panythingelse is taken as the Sendmail-compatible argument -prval:sval,
which sets the host protocol and host name */
- if (*argrest == 0)
- if (i+1 < argc)
- argrest = argv[++i];
- else
- { badarg = TRUE; break; }
+ if (!*argrest)
+ if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
- if (*argrest != 0)
+ if (*argrest)
{
- uschar *hn;
+ uschar * hn = Ustrchr(argrest, ':');
if (received_protocol)
exim_fail("received_protocol is set already\n");
- hn = Ustrchr(argrest, ':');
- if (hn == NULL)
- received_protocol = argrest;
+ if (!hn)
+ received_protocol = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_DRIVERNAME_MAX, "-p<protocol>"), TRUE);
else
{
- int old_pool = store_pool;
- store_pool = POOL_PERM;
- received_protocol = string_copyn(argrest, hn - argrest);
- store_pool = old_pool;
- sender_host_name = hn + 1;
+ (void) exim_str_fail_toolong(argrest, (EXIM_DRIVERNAME_MAX+1+EXIM_HOSTNAME_MAX), "-p<protocol>:<host>");
+ received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE);
+ sender_host_name = string_copy_taint(hn + 1, TRUE);
}
}
break;
{
int i;
for (argrest++, i = 0; argrest[i] && argrest[i] != '/'; ) i++;
+ exim_len_fail_toolong(i, EXIM_DRIVERNAME_MAX, "-q*G<name>");
queue_name = string_copyn(argrest, i);
argrest += i;
if (*argrest == '/') argrest++;
only, optionally named, optionally starting from a given message id. */
if (!(list_queue || count_queue))
- if (*argrest == 0
+ if ( !*argrest
&& (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1])))
{
queue_interval = 0;
if (i+1 < argc && mac_ismsgid(argv[i+1]))
- start_queue_run_id = argv[++i];
+ start_queue_run_id = string_copy_taint(argv[++i], TRUE);
if (i+1 < argc && mac_ismsgid(argv[i+1]))
- stop_queue_run_id = argv[++i];
+ stop_queue_run_id = string_copy_taint(argv[++i], TRUE);
}
/* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally
case 'R': /* Synonymous with -qR... */
- receiving_message = FALSE;
+ {
+ const uschar *tainted_selectstr;
+
+ receiving_message = FALSE;
/* -Rf: As -R (below) but force all deliveries,
-Rff: Ditto, but also thaw all frozen messages,
in all cases provided there are no further characters in this
argument. */
- if (*argrest != 0)
- for (int i = 0; i < nelem(rsopts); i++)
- if (Ustrcmp(argrest, rsopts[i]) == 0)
- {
- if (i != 2) f.queue_run_force = TRUE;
- if (i >= 2) f.deliver_selectstring_regex = TRUE;
- if (i == 1 || i == 4) f.deliver_force_thaw = TRUE;
- argrest += Ustrlen(rsopts[i]);
- }
+ if (*argrest)
+ for (int i = 0; i < nelem(rsopts); i++)
+ if (Ustrcmp(argrest, rsopts[i]) == 0)
+ {
+ if (i != 2) f.queue_run_force = TRUE;
+ if (i >= 2) f.deliver_selectstring_regex = TRUE;
+ if (i == 1 || i == 4) f.deliver_force_thaw = TRUE;
+ argrest += Ustrlen(rsopts[i]);
+ }
/* -R: Set string to match in addresses for forced queue run to
pick out particular messages. */
- if (*argrest)
- deliver_selectstring = argrest;
- else if (i+1 < argc)
- deliver_selectstring = argv[++i];
- else
- exim_fail("exim: string expected after -R\n");
+ /* Avoid attacks from people providing very long strings, and do so before
+ we make copies. */
+ if (*argrest)
+ tainted_selectstr = argrest;
+ else if (i+1 < argc)
+ tainted_selectstr = argv[++i];
+ else
+ exim_fail("exim: string expected after -R\n");
+ deliver_selectstring = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-R"), TRUE);
+ }
break;
-
/* -r: an obsolete synonym for -f (see above) */
/* -S: Like -R but works on sender. */
case 'S': /* Synonymous with -qS... */
- receiving_message = FALSE;
+ {
+ const uschar *tainted_selectstr;
+
+ receiving_message = FALSE;
/* -Sf: As -S (below) but force all deliveries,
-Sff: Ditto, but also thaw all frozen messages,
in all cases provided there are no further characters in this
argument. */
- if (*argrest)
- for (int i = 0; i < nelem(rsopts); i++)
- if (Ustrcmp(argrest, rsopts[i]) == 0)
- {
- if (i != 2) f.queue_run_force = TRUE;
- if (i >= 2) f.deliver_selectstring_sender_regex = TRUE;
- if (i == 1 || i == 4) f.deliver_force_thaw = TRUE;
- argrest += Ustrlen(rsopts[i]);
- }
+ if (*argrest)
+ for (int i = 0; i < nelem(rsopts); i++)
+ if (Ustrcmp(argrest, rsopts[i]) == 0)
+ {
+ if (i != 2) f.queue_run_force = TRUE;
+ if (i >= 2) f.deliver_selectstring_sender_regex = TRUE;
+ if (i == 1 || i == 4) f.deliver_force_thaw = TRUE;
+ argrest += Ustrlen(rsopts[i]);
+ }
/* -S: Set string to match in addresses for forced queue run to
pick out particular messages. */
- if (*argrest)
- deliver_selectstring_sender = argrest;
- else if (i+1 < argc)
- deliver_selectstring_sender = argv[++i];
- else
- exim_fail("exim: string expected after -S\n");
+ if (*argrest)
+ tainted_selectstr = argrest;
+ else if (i+1 < argc)
+ tainted_selectstr = argv[++i];
+ else
+ exim_fail("exim: string expected after -S\n");
+ deliver_selectstring_sender = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-S"), TRUE);
+ }
break;
/* -Tqt is an option that is exclusively for use by the testing suite.
case 'T':
if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0)
- fudged_queue_times = argv[++i];
+ fudged_queue_times = string_copy_taint(argv[++i], TRUE);
else badarg = TRUE;
break;
/* -t: Set flag to extract recipients from body of message. */
case 't':
- if (*argrest == 0) extract_recipients = TRUE;
+ if (!*argrest) extract_recipients = TRUE;
/* -ti: Set flag to extract recipients from body of message, and also
specify that dot does not end the message. */
/* -v: verify things - this is a very low-level debugging */
case 'v':
- if (*argrest == 0)
+ if (!*argrest)
{
debug_selector |= D_v;
debug_file = stderr;
As Exim is 8-bit clean, it just ignores this flag. */
case 'x':
- if (*argrest != 0) badarg = TRUE;
+ if (*argrest) badarg = TRUE;
break;
/* -X: in sendmail: takes one parameter, logfile, and sends debugging
logs to that file. We swallow the parameter and otherwise ignore it. */
case 'X':
- if (*argrest == '\0')
+ if (!*argrest)
if (++i >= argc)
exim_fail("exim: string expected after -X\n");
break;
+ /* -z: a line of text to log */
+
case 'z':
- if (*argrest == '\0')
+ if (!*argrest)
if (++i < argc)
- log_oneline = argv[i];
+ log_oneline = string_copy_taint(exim_str_fail_toolong(argv[i], 2048, "-z logtext"), TRUE);
else
exim_fail("exim: file name expected after %s\n", argv[i-1]);
break;
/* If -R or -S have been specified without -q, assume a single queue run. */
-if ( (deliver_selectstring || deliver_selectstring_sender)
- && queue_interval < 0)
- queue_interval = 0;
+ if ( (deliver_selectstring || deliver_selectstring_sender)
+ && queue_interval < 0)
+ queue_interval = 0;
END_ARG:
+ store_pool = old_pool;
+ }
+
/* If usage_wanted is set we call the usage function - which never returns */
if (usage_wanted) exim_usage(called_as);
/* Store the initial cwd before we change directories. Can be NULL if the
dir has already been unlinked. */
+errno = 0;
initial_cwd = os_getcwd(NULL, 0);
+if (!initial_cwd && errno)
+ exim_fail("exim: getting initial cwd failed: %s\n", strerror(errno));
+
+if (initial_cwd && (strlen(CCS initial_cwd) >= BIG_BUFFER_SIZE))
+ exim_fail("exim: initial cwd is far too long (%d)\n", Ustrlen(CCS initial_cwd));
/* checking:
-be[m] expansion test -
p = big_buffer + 3;
}
printing = string_printing(argv[i]);
- if (printing[0] == 0) quote = US"\""; else
+ if (!*printing) quote = US"\"";
+ else
{
const uschar *pp = printing;
quote = US"";
- while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; }
+ while (*pp) if (isspace(*pp++)) { quote = US"\""; break; }
}
p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size -
(p - big_buffer) - 4), printing, quote);
if (bi_option)
{
(void)fclose(config_file);
- if (bi_command != NULL)
+ if (bi_command)
{
int i = 0;
uschar *argv[3];
argv[i++] = bi_command;
- if (alias_arg != NULL) argv[i++] = alias_arg;
+ if (alias_arg) argv[i++] = alias_arg;
argv[i++] = NULL;
setgroups(group_count, group_list);
exim_setugid(real_uid, real_gid, FALSE, US"running bi_command");
DEBUG(D_exec) debug_printf("exec %.256s %.256s\n", argv[0],
- (argv[1] == NULL)? US"" : argv[1]);
+ argv[1] ? argv[1] : US"");
execv(CS argv[0], (char *const *)argv);
exim_fail("exim: exec failed: %s\n", strerror(errno));
if (!(unprivileged || removed_privilege))
exim_fail("exim: changing group failed: %s\n", strerror(errno));
else
+ {
DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n",
(long int)exim_gid, strerror(errno));
+ }
}
/* Handle a request to scan a file for malware */
retry_config *yield;
int basic_errno = 0;
int more_errno = 0;
- uschar *s1, *s2;
+ const uschar *s1, *s2;
if (test_retry_arg >= argc)
{
printf("-brt needs a domain or address argument\n");
exim_exit(EXIT_FAILURE);
}
- s1 = argv[test_retry_arg++];
+ s1 = exim_str_fail_toolong(argv[test_retry_arg++], EXIM_EMAILADDR_MAX, "-brt");
s2 = NULL;
/* If the first argument contains no @ and no . it might be a local user
/* There may be an optional second domain arg. */
if (test_retry_arg < argc && Ustrchr(argv[test_retry_arg], '.') != NULL)
- s2 = argv[test_retry_arg++];
+ s2 = exim_str_fail_toolong(argv[test_retry_arg++], EXIM_DOMAINNAME_MAX, "-brt 2nd");
/* The final arg is an error name */
if (test_retry_arg < argc)
{
- uschar *ss = argv[test_retry_arg];
+ const uschar *ss = exim_str_fail_toolong(argv[test_retry_arg], EXIM_DRIVERNAME_MAX, "-brt 3rd");
uschar *error =
readconf_retry_error(ss, ss + Ustrlen(ss), &basic_errno, &more_errno);
if (error != NULL)
Ustrcmp(argv[i], "macro") == 0 ||
Ustrcmp(argv[i], "environment") == 0))
{
- fail |= !readconf_print(argv[i+1], argv[i], flag_n);
+ fail |= !readconf_print(exim_str_fail_toolong(argv[i+1], EXIM_DRIVERNAME_MAX, "-bP name"), argv[i], flag_n);
i++;
}
else
- fail = !readconf_print(argv[i], NULL, flag_n);
+ fail = !readconf_print(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-bP item"), NULL, flag_n);
}
exim_exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
}
{
int status;
pid_t pid;
+ /*XXX This use of argv[i] for msg_id should really be tainted, but doing
+ that runs into a later copy into the untainted global message_id[] */
+ /*XXX Do we need a length limit check here? */
if (i == argc - 1)
(void)deliver_message(argv[i], forced_delivery, deliver_give_up);
else if ((pid = exim_fork(US"cmdline-delivery")) == 0)
/* Ensure that the user name is in a suitable form for use as a "phrase" in an
RFC822 address.*/
-originator_name = string_copy(parse_fix_phrase(originator_name,
- Ustrlen(originator_name), big_buffer, big_buffer_size));
+originator_name = parse_fix_phrase(originator_name, Ustrlen(originator_name));
/* If a message is created by this call of Exim, the uid/gid of its originator
are those of the caller. These values are overridden if an existing message is
printf("-brw needs an address argument\n");
exim_exit(EXIT_FAILURE);
}
- rewrite_test(argv[test_rewrite_arg]);
+ rewrite_test(exim_str_fail_toolong(argv[test_rewrite_arg], EXIM_EMAILADDR_MAX, "-brw"));
exim_exit(EXIT_SUCCESS);
}
while (recipients_arg < argc)
{
/* Supplied addresses are tainted since they come from a user */
- uschar * s = string_copy_taint(argv[recipients_arg++], TRUE);
+ uschar * s = string_copy_taint(exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, "address verification"), TRUE);
while (*s)
{
BOOL finished = FALSE;
{
uschar * s = get_stdinput(NULL, NULL);
if (!s) break;
- test_address(string_copy_taint(s, TRUE), flags, &exit_value);
+ test_address(string_copy_taint(exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, "address verification (stdin)"), TRUE), flags, &exit_value);
}
route_tidyup();
dns_init(FALSE, FALSE, FALSE);
if (msg_action_arg > 0 && msg_action == MSG_LOAD)
{
- uschar spoolname[256]; /* Not big_buffer; used in spool_read_header() */
+ uschar * spoolname;
if (!f.admin_user)
exim_fail("exim: permission denied\n");
- message_id = argv[msg_action_arg];
- (void)string_format(spoolname, sizeof(spoolname), "%s-H", message_id);
+ message_id = US exim_str_fail_toolong(argv[msg_action_arg], MESSAGE_ID_LENGTH, "message-id");
+ /* Checking the length of the ID is sufficient to validate it.
+ Get an untainted version so file opens can be done. */
+ message_id = string_copy_taint(message_id, FALSE);
+
+ spoolname = string_sprintf("%s-H", message_id);
if ((deliver_datafile = spool_open_datafile(message_id)) < 0)
printf ("Failed to load message datafile %s\n", message_id);
if (spool_read_header(spoolname, TRUE, FALSE) != spool_read_OK)
if (recipients_arg < argc)
while (recipients_arg < argc)
- expansion_test_line(argv[recipients_arg++]);
+ expansion_test_line(exim_str_fail_toolong(argv[recipients_arg++], EXIM_EMAILADDR_MAX, "recipient"));
/* Read stdin */
if (smtp_start_session())
{
+ rmark reset_point;
for (; (reset_point = store_mark()); store_reset(reset_point))
{
if (smtp_setup_msg() <= 0) break;
deliver_localpart_orig = NULL;
deliver_domain_orig = NULL;
callout_address = sending_ip_address = NULL;
+ deliver_localpart_data = deliver_domain_data =
+ recipient_data = sender_data = NULL;
sender_rate = sender_rate_limit = sender_rate_period = NULL;
}
smtp_log_no_mail();
while (more)
{
- reset_point = store_mark();
+ rmark reset_point = store_mark();
message_id[0] = 0;
/* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP
{
int start, end, domain;
uschar * errmess;
- uschar * s = string_copy_taint(list[i], TRUE);
+ /* 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. */
+ uschar * s = string_copy_taint(exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"), TRUE);
/* Loop for each comma-separated address */
errmess = US"unqualified recipient address not allowed";
}
- if (recipient == NULL)
- {
+ if (!recipient)
if (error_handling == ERRORS_STDERR)
{
fprintf(stderr, "exim: bad recipient address \"%s\": %s\n",
moan_to_sender(ERRMESS_BADARGADDRESS, &eblock, NULL, stdin, TRUE)?
errors_sender_rc : EXIT_FAILURE;
}
- }
receive_add_recipient(string_copy_taint(recipient, TRUE), -1);
s = ss;
DEBUG(D_receive)
{
- if (sender_address != NULL) debug_printf("Sender: %s\n", sender_address);
- if (recipients_list != NULL)
+ if (sender_address) debug_printf("Sender: %s\n", sender_address);
+ if (recipients_list)
{
debug_printf("Recipients:\n");
for (int i = 0; i < recipients_count; i++)
if (filter_test != FTEST_NONE)
{
- deliver_domain = (ftest_domain != NULL)?
- ftest_domain : qualify_domain_recipient;
+ deliver_domain = ftest_domain ? ftest_domain : qualify_domain_recipient;
deliver_domain_orig = deliver_domain;
- deliver_localpart = (ftest_localpart != NULL)?
- ftest_localpart : originator_login;
+ deliver_localpart = ftest_localpart ? US ftest_localpart : originator_login;
deliver_localpart_orig = deliver_localpart;
- deliver_localpart_prefix = ftest_prefix;
- deliver_localpart_suffix = ftest_suffix;
+ deliver_localpart_prefix = US ftest_prefix;
+ deliver_localpart_suffix = US ftest_suffix;
deliver_home = originator_home;
- if (return_path == NULL)
+ if (!return_path)
{
printf("Return-path copied from sender\n");
return_path = string_copy(sender_address);
receive_add_recipient(
string_sprintf("%s%s%s@%s",
- (ftest_prefix == NULL)? US"" : ftest_prefix,
+ ftest_prefix ? ftest_prefix : US"",
deliver_localpart,
- (ftest_suffix == NULL)? US"" : ftest_suffix,
+ ftest_suffix ? ftest_suffix : US"",
deliver_domain), -1);
printf("Recipient = %s\n", recipients_list[0].address);
- if (ftest_prefix != NULL) printf("Prefix = %s\n", ftest_prefix);
- if (ftest_suffix != NULL) printf("Suffix = %s\n", ftest_suffix);
+ if (ftest_prefix) printf("Prefix = %s\n", ftest_prefix);
+ if (ftest_suffix) printf("Suffix = %s\n", ftest_suffix);
if (chdir("/")) /* Get away from wherever the user is running this from */
{
available to the user filter. We need to copy the filter variables
explicitly. */
- if ((filter_test & FTEST_SYSTEM) != 0)
+ if (filter_test & FTEST_SYSTEM)
if (!filter_runtest(filter_sfd, filter_test_sfile, TRUE, more))
exim_exit(EXIT_FAILURE);
memcpy(filter_sn, filter_n, sizeof(filter_sn));
- if ((filter_test & FTEST_USER) != 0)
+ if (filter_test & FTEST_USER)
if (!filter_runtest(filter_ufd, filter_test_ufile, FALSE, more))
exim_exit(EXIT_FAILURE);
will be TRUE. If it is not, check on the number of messages received in this
connection. */
- if (!session_local_queue_only &&
- smtp_accept_queue_per_connection > 0 &&
- receive_messagecount > smtp_accept_queue_per_connection)
+ if ( !session_local_queue_only
+ && smtp_accept_queue_per_connection > 0
+ && receive_messagecount > smtp_accept_queue_per_connection)
{
session_local_queue_only = TRUE;
queue_only_reason = 2;
ones. However, there are odd cases where this is not wanted, so this can be
changed by setting queue_only_load_latch false. */
- local_queue_only = session_local_queue_only;
- if (!local_queue_only && queue_only_load >= 0)
- {
- local_queue_only = (load_average = OS_GETLOADAVG()) > queue_only_load;
- if (local_queue_only)
+ if (!(local_queue_only = session_local_queue_only) && queue_only_load >= 0)
+ if ((local_queue_only = (load_average = OS_GETLOADAVG()) > queue_only_load))
{
queue_only_reason = 3;
if (queue_only_load_latch) session_local_queue_only = TRUE;
}
- }
/* If running as an MUA wrapper, all queueing options and freezing options
are ignored. */
#endif
callout_address = NULL;
sending_ip_address = NULL;
+ deliver_localpart_data = deliver_domain_data =
+ recipient_data = sender_data = NULL;
acl_var_m = NULL;
for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;