static void *
function_store_get(size_t size)
{
-return store_get((int)size);
+/* For now, regard all RE results as potentially tainted. We might need
+more intelligence on this point. */
+return store_get((int)size, TRUE);
}
static void
g = string_fmt_append(&gs, "%5d ", (int)getpid());
len = g->ptr;
va_start(ap, format);
-if (!string_vformat(g, FALSE, format, ap))
+if (!string_vformat(g, 0, format, ap))
{
gs.ptr = len;
g = string_cat(&gs, US"**** string overflowed buffer ****");
}
-
-
/*************************************************
* Ensure stdin, stdout, and stderr exist *
*************************************************/
{
if (devnull < 0) devnull = open("/dev/null", O_RDWR);
if (devnull < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
- string_open_failed(errno, "/dev/null"));
+ string_open_failed(errno, "/dev/null", NULL));
if (devnull != i) (void)dup2(devnull, i);
}
}
{
if (smtp_input)
{
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
tls_close(NULL, TLS_NO_SHUTDOWN); /* Shut down the TLS library */
#endif
(void)close(fileno(smtp_in));
exim_exit(int rc, const uschar * process)
{
search_tidyup();
+store_exit();
DEBUG(D_any)
debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d "
">>>>>>>>>>>>>>>>\n", (int)getpid(),
}
+void
+exim_underbar_exit(int rc)
+{
+store_exit();
+_exit(rc);
+}
+
+
/* Print error string, then die */
static void
exit(EXIT_FAILURE);
}
+/* exim_chown_failure() called from exim_chown()/exim_fchown() on failure
+of chown()/fchown(). See src/functions.h for more explanation */
+int
+exim_chown_failure(int fd, const uschar *name, uid_t owner, gid_t group)
+{
+int saved_errno = errno; /* from the preceeding chown call */
+#if 1
+log_write(0, LOG_MAIN|LOG_PANIC,
+ __FILE__ ":%d: chown(%s, %d:%d) failed (%s)."
+ " Please contact the authors and refer to https://bugs.exim.org/show_bug.cgi?id=2391",
+ __LINE__, name?name:US"<unknown>", owner, group, strerror(errno));
+#else
+/* I leave this here, commented, in case the "bug"(?) comes up again.
+ It is not an Exim bug, but we can provide a workaround.
+ See Bug 2391
+ HS 2019-04-18 */
+
+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
+errno = saved_errno;
+return -1;
+}
/*************************************************
#ifdef USE_TCP_WRAPPERS
fprintf(fp, " TCPwrappers");
#endif
-#ifdef SUPPORT_TLS
-# ifdef USE_GNUTLS
+#ifdef USE_GNUTLS
fprintf(fp, " GnuTLS");
-# else
+#endif
+#ifdef USE_OPENSSL
fprintf(fp, " OpenSSL");
-# endif
#endif
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
fprintf(fp, " translate_ip_address");
#ifndef DISABLE_OCSP
fprintf(fp, " OCSP");
#endif
+#ifdef SUPPORT_PIPE_CONNECT
+ fprintf(fp, " PIPE_CONNECT");
+#endif
#ifndef DISABLE_PRDR
fprintf(fp, " PRDR");
#endif
#ifdef SUPPORT_SPF
fprintf(fp, " SPF");
#endif
+#ifdef SUPPORT_DMARC
+ fprintf(fp, " DMARC");
+#endif
#ifdef TCP_FASTOPEN
deliver_init();
if (f.tcp_fastopen_ok) fprintf(fp, " TCP_Fast_Open");
#ifdef EXPERIMENTAL_DCC
fprintf(fp, " Experimental_DCC");
#endif
-#ifdef EXPERIMENTAL_DMARC
- fprintf(fp, " Experimental_DMARC");
-#endif
#ifdef EXPERIMENTAL_DSN_INFO
fprintf(fp, " Experimental_DSN_info");
#endif
-#ifdef EXPERIMENTAL_PIPE_CONNECT
- fprintf(fp, " Experimental_PIPE_CONNECT");
+#ifdef EXPERIMENTAL_TLS_RESUME
+ fprintf(fp, " Experimental_TLS_resume");
#endif
fprintf(fp, "\n");
show_db_version(fp);
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
tls_version_report(fp);
#endif
#ifdef SUPPORT_I18N
#ifdef USE_READLINE
char *readline_line = NULL;
- if (fn_readline != NULL)
+ if (fn_readline)
{
- if ((readline_line = fn_readline((i > 0)? "":"> ")) == NULL) break;
- if (*readline_line != 0 && fn_addhist != NULL) fn_addhist(readline_line);
+ if (!(readline_line = fn_readline((i > 0)? "":"> "))) break;
+ if (*readline_line != 0 && fn_addhist) fn_addhist(readline_line);
p = US readline_line;
}
else
while (ss > p && isspace(ss[-1])) ss--;
if (i > 0)
- {
while (p < ss && isspace(*p)) p++; /* leading space after cont */
- }
g = string_catn(g, p, ss - p);
}
/* Get a list of macros which are whitelisted */
-whitelisted = string_copy_malloc(US WHITELIST_D_MACROS);
+whitelisted = string_copy_perm(US WHITELIST_D_MACROS, FALSE);
prev_char_item = FALSE;
white_count = 0;
for (p = whitelisted; *p != '\0'; ++p)
uschar *real_sender_address;
uschar *originator_home = US"/";
size_t sz;
-void *reset_point;
+rmark reset_point;
struct passwd *pw;
struct stat statbuf;
/* Set up the handler for the data request signal, and set the initial
descriptive text. */
+process_info = store_get(PROCESS_INFO_SIZE, TRUE); /* tainted */
set_process_info("initializing");
os_restarting_signal(SIGUSR1, usr1_handler);
else
{
/* Well, the trust list at least is up to scratch... */
- void *reset_point = store_get(0);
+ rmark reset_point = store_mark();
uschar *trusted_configs[32];
int nr_configs = 0;
int i = 0;
&sep, big_buffer, big_buffer_size)) != NULL)
{
for (i=0; i < nr_configs; i++)
- {
if (Ustrcmp(filename, trusted_configs[i]) == 0)
break;
- }
if (i == nr_configs)
{
f.trusted_config = FALSE;
break;
}
}
- store_reset(reset_point);
}
- else
- {
- /* No valid prefixes found in trust_list file. */
+ else /* No valid prefixes found in trust_list file. */
f.trusted_config = FALSE;
- }
+ store_reset(reset_point);
}
}
- else
- {
- /* Could not open trust_list file. */
+ else /* Could not open trust_list file. */
f.trusted_config = FALSE;
- }
}
#else
/* Not root; don't trust config */
if (clmacro_count >= MAX_CLMACROS)
exim_fail("exim: too many -D options on command line\n");
- clmacros[clmacro_count++] = string_sprintf("-D%s=%s", m->name,
- m->replacement);
+ clmacros[clmacro_count++] =
+ string_sprintf("-D%s=%s", m->name, m->replacement);
}
#endif
break;
{ badarg = TRUE; break; }
}
if (*argrest == 0)
- sender_address = string_sprintf(""); /* Ensure writeable memory */
+ *(sender_address = store_get(1, FALSE)) = '\0'; /* Ensure writeable memory */
else
{
uschar *temp = argrest + Ustrlen(argrest) - 1;
#endif
sender_address = parse_extract_address(argrest, &errmess,
&dummy_start, &dummy_end, &sender_address_domain, TRUE);
+ sender_address = string_copy_taint(sender_address, TRUE);
#ifdef SUPPORT_I18N
message_smtputf8 = string_is_utf8(sender_address);
allow_utf8_domains = FALSE;
case 'S': smtp_peer_options |= OPTION_SIZE; break;
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
/* -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,
/* -oMas: setting authenticated sender */
- else if (Ustrcmp(argrest, "Mas") == 0) authenticated_sender = argv[++i];
+ else if (Ustrcmp(argrest, "Mas") == 0)
+ authenticated_sender = string_copy_taint(argv[++i], TRUE);
/* -oMai: setting authenticated id */
- else if (Ustrcmp(argrest, "Mai") == 0) authenticated_id = argv[++i];
+ else if (Ustrcmp(argrest, "Mai") == 0)
+ authenticated_id = string_copy_taint(argv[++i], TRUE);
/* -oMi: Set incoming interface address */
/* -oMs: Set sender host name */
- else if (Ustrcmp(argrest, "Ms") == 0) sender_host_name = argv[++i];
+ else if (Ustrcmp(argrest, "Ms") == 0)
+ sender_host_name = string_copy_taint(argv[++i], TRUE);
/* -oMt: Set sender ident */
/* -q[f][f][l][G<name>]: Run the queue, optionally forced, optionally local
only, optionally named, optionally starting from a given message id. */
- if (*argrest == 0 &&
- (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];
- if (i+1 < argc && mac_ismsgid(argv[i+1]))
- stop_queue_run_id = argv[++i];
- }
+ if (!(list_queue || count_queue))
+ if (*argrest == 0
+ && (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];
+ if (i+1 < argc && mac_ismsgid(argv[i+1]))
+ stop_queue_run_id = argv[++i];
+ }
/* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally
forced, optionally local only, optionally named. */
- else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i],
- 0, FALSE)) <= 0)
- exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
+ else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i],
+ 0, FALSE)) <= 0)
+ exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
break;
/* -tls-on-connect: don't wait for STARTTLS (for old clients) */
- #ifdef SUPPORT_TLS
+ #ifndef DISABLE_TLS
else if (Ustrcmp(argrest, "ls-on-connect") == 0) tls_in.on_connect = TRUE;
#endif
&& f.really_exim && !list_options && !checking)
{
uschar *p = big_buffer;
- Ustrcpy(p, "cwd= (failed)");
+ Ustrcpy(p, US"cwd= (failed)");
if (!initial_cwd)
p += 13;
uschar *quote;
if (p + len + 8 >= big_buffer + big_buffer_size)
{
- Ustrcpy(p, " ...");
+ Ustrcpy(p, US" ...");
log_write(0, LOG_MAIN, "%s", big_buffer);
- Ustrcpy(big_buffer, "...");
+ Ustrcpy(big_buffer, US"...");
p = big_buffer + 3;
}
printing = string_printing(argv[i]);
else
{
int rv;
+ DEBUG(D_any) debug_printf("dropping to exim gid; retaining priv uid\n");
rv = setgid(exim_gid);
/* Impact of failure is that some stuff might end up with an incorrect group.
We track this for failures from root, since any attempt to change privilege
readconf_rest();
-/* The configuration data will have been read into POOL_PERM because we won't
-ever want to reset back past it. Change the current pool to POOL_MAIN. In fact,
-this is just a bit of pedantic tidiness. It wouldn't really matter if the
-configuration were read into POOL_MAIN, because we don't do any resets till
-later on. However, it seems right, and it does ensure that both pools get used.
-*/
-
-store_pool = POOL_MAIN;
-
/* Handle the -brt option. This is for checking out retry configurations.
The next three arguments are a domain name or a complete address, and
optionally two error numbers. All it does is to call the function that
else if ((pid = fork()) == 0)
{
(void)deliver_message(argv[i], forced_delivery, deliver_give_up);
- _exit(EXIT_SUCCESS);
+ exim_underbar_exit(EXIT_SUCCESS);
}
else if (pid < 0)
{
the caller. This will get overwritten below for an inetd call. If a trusted
caller has set it empty, unset it. */
-if (sender_ident == NULL) sender_ident = originator_login;
- else if (sender_ident[0] == 0) sender_ident = NULL;
+if (!sender_ident) sender_ident = originator_login;
+else if (!*sender_ident) sender_ident = NULL;
/* Handle the -brw option, which is for checking out rewriting rules. Cause log
writes (on errors) to go to stderr instead. Can't do this earlier, as want the
unless a trusted caller supplies a sender address with -f, or is passing in the
message via SMTP (inetd invocation or otherwise). */
-if ((sender_address == NULL && !smtp_input) ||
- (!f.trusted_caller && filter_test == FTEST_NONE))
+if ( !sender_address && !smtp_input
+ || !f.trusted_caller && filter_test == FTEST_NONE)
{
f.sender_local = TRUE;
via -oMas and -oMai and if so, they will already be set. Otherwise, force
defaults except when host checking. */
- if (authenticated_sender == NULL && !host_checking)
+ if (!authenticated_sender && !host_checking)
authenticated_sender = string_sprintf("%s@%s", originator_login,
qualify_domain_sender);
- if (authenticated_id == NULL && !host_checking)
+ if (!authenticated_id && !host_checking)
authenticated_id = originator_login;
}
specify a sender address for SMTP input, we leave sender_address unset. This
causes the MAIL commands to be honoured. */
-if ((!smtp_input && sender_address == NULL) ||
- !receive_check_set_sender(sender_address))
+if ( !smtp_input && !sender_address
+ || !receive_check_set_sender(sender_address))
{
/* Either the caller is not permitted to set a general sender, or this is
non-SMTP input and the trusted caller has not set a sender. If there is no
address, which indicates an error message, or doesn't exist (root caller, smtp
interface, no -f argument). */
-if (sender_address != NULL && sender_address[0] != 0 &&
- sender_address_domain == 0)
+if (sender_address && *sender_address && sender_address_domain == 0)
sender_address = string_sprintf("%s@%s", local_part_quote(sender_address),
qualify_domain_sender);
it. The code works for both IPv4 and IPv6, as it happens. */
size = host_aton(sender_host_address, x);
- sender_host_address = store_get(48); /* large enough for full IPv6 */
+ sender_host_address = store_get(48, FALSE); /* large enough for full IPv6 */
(void)host_nmtoa(size, x, -1, sender_host_address, ':');
/* Now set up for testing */
if (smtp_start_session())
{
- for (reset_point = store_get(0); ; store_reset(reset_point))
+ for (; (reset_point = store_mark()); store_reset(reset_point))
{
if (smtp_setup_msg() <= 0) break;
if (!receive_msg(FALSE)) break;
/* Save the current store pool point, for resetting at the start of
each message, and save the real sender address, if any. */
-reset_point = store_get(0);
real_sender_address = sender_address;
/* Loop to receive messages; receive_msg() returns TRUE if there are more
while (more)
{
+ reset_point = store_mark();
message_id[0] = 0;
/* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP
}
}
- receive_add_recipient(recipient, -1);
+ receive_add_recipient(string_copy_taint(recipient, TRUE), -1);
s = ss;
if (!finished)
while (*(++s) != 0 && (*s == ',' || isspace(*s)));
rc = deliver_message(message_id, FALSE, FALSE);
search_tidyup();
- _exit((!mua_wrapper || rc == DELIVER_MUA_SUCCEEDED)?
- EXIT_SUCCESS : EXIT_FAILURE);
+ exim_underbar_exit(!mua_wrapper || rc == DELIVER_MUA_SUCCEEDED
+ ? EXIT_SUCCESS : EXIT_FAILURE);
}
if (pid < 0)