*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
}
static void
-function_dummy_free(void *block) { block = block; }
+function_dummy_free(void * block) {}
static void *
function_store_malloc(size_t size)
}
static void
-function_store_free(void *block)
+function_store_free(void * block)
{
store_free(block);
}
void
sigalrm_handler(int sig)
{
-sig = sig; /* Keep picky compilers happy */
sigalrm_seen = TRUE;
os_non_restarting_signal(SIGALRM, sigalrm_handler);
}
void
millisleep(int msec)
{
-struct itimerval itval;
-itval.it_interval.tv_sec = 0;
-itval.it_interval.tv_usec = 0;
-itval.it_value.tv_sec = msec/1000;
-itval.it_value.tv_usec = (msec % 1000) * 1000;
+struct itimerval itval = {.it_interval = {.tv_sec = 0, .tv_usec = 0},
+ .it_value = {.tv_sec = msec/1000,
+ .tv_usec = (msec % 1000) * 1000}};
milliwait(&itval);
}
*************************************************/
#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)
{
{
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", NULL));
+ string_open_failed("/dev/null", NULL));
if (devnull != i) (void)dup2(devnull, i);
}
}
*/
void
-exim_exit(int rc, const uschar * process)
+exim_exit(int rc)
{
search_tidyup();
store_exit();
DEBUG(D_any)
- debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d "
- ">>>>>>>>>>>>>>>>\n", (int)getpid(),
- process ? "(" : "", process, process ? ") " : "", rc);
+ debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d (%s) terminating with rc=%d "
+ ">>>>>>>>>>>>>>>>\n",
+ (int)getpid(), process_purpose, rc);
exit(rc);
}
void
-exim_underbar_exit(int rc, const uschar * process)
+exim_underbar_exit(int rc)
{
store_exit();
DEBUG(D_any)
- debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d "
- ">>>>>>>>>>>>>>>>\n", (int)getpid(),
- process ? "(" : "", process, process ? ") " : "", rc);
+ debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d (%s) terminating with rc=%d "
+ ">>>>>>>>>>>>>>>>\n",
+ (int)getpid(), process_purpose, rc);
_exit(rc);
}
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
+#ifndef DISABLE_TLS_RESUME
+ g = string_cat(g, US" TLS_resume");
#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
+#ifdef SUPPORT_DMARC
+ g = string_cat(g, US" DMARC");
#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
+#ifndef DISABLE_QUEUE_RAMP
+ g = string_cat(g, US" Experimental_Queue_Ramp");
#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");
+#if defined(SUPPORT_SRS)
+ g = string_cat(g, US" SRS");
#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");
-#endif
-#ifdef EXPERIMENTAL_LMDB
- fprintf(fp, " Experimental_LMDB");
-#endif
-#ifdef EXPERIMENTAL_QUEUE_RAMP
- fprintf(fp, " Experimental_Queue_Ramp");
+ g = string_cat(g, US" Experimental_DSN_info");
#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");
+#if defined(EXPERIMENTAL_SRS_ALT)
+ g = string_cat(g, US" Experimental_SRS");
#endif
-#ifdef EXPERIMENTAL_TLS_RESUME
- fprintf(fp, " 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");
+#ifdef LOOKUP_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);
}
BOOL usage_wanted = FALSE;
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 *real_sender_address;
uschar *originator_home = US"/";
size_t sz;
-rmark reset_point;
struct passwd *pw;
struct stat statbuf;
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];
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;
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;
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. */
case 'D': smtp_peer_options |= OPTION_DSN; break;
+ /* -MCd: for debug, set a process-purpose string */
+
+ case 'd': if (++i < argc)
+ process_purpose = string_copy_taint(argv[i], TRUE);
+ else badarg = TRUE;
+ break;
+
/* -MCG: set the queue name, to a non-default value */
case 'G': if (++i < argc) queue_name = string_copy_taint(argv[i], TRUE);
else badarg = TRUE;
break;
+ /* -MCq: do a quota check on the given recipient for the given size
+ of message. Separate from -MC. */
+ case 'q': rcpt_verify_quota = TRUE;
+ if (++i < argc) message_size = Uatoi(argv[i]);
+ else badarg = TRUE;
+ break;
+
/* -MCS: set the smtp_use_size flag; this is useful only when it
precedes -MC (see above) */
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(argv[i], 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 = string_copy_taint(argv[i], TRUE);
else override_local_interfaces = string_copy_taint(argv[++i], TRUE);
break;
+ /* -oY: Override creation of daemon notifier socket */
+
+ case 'Y':
+ if (*argrest) badarg = TRUE;
+ else notifier_socket = NULL;
+ break;
+
/* Unknown -o argument */
default:
if (*argrest)
{
- uschar *hn;
+ uschar * hn = Ustrchr(argrest, ':');
if (received_protocol)
exim_fail("received_protocol is set already\n");
- hn = Ustrchr(argrest, ':');
if (!hn)
received_protocol = string_copy_taint(argrest, TRUE);
else
{
- int old_pool = store_pool;
- store_pool = POOL_PERM;
received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE);
- store_pool = old_pool;
sender_host_name = string_copy_taint(hn + 1, TRUE);
}
}
/* 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);
/* Arguments have been processed. Check for incompatibilities. */
-if ((
- (smtp_input || extract_recipients || recipients_arg < argc) &&
- (f.daemon_listen || queue_interval >= 0 || bi_option ||
- test_retry_arg >= 0 || test_rewrite_arg >= 0 ||
- filter_test != FTEST_NONE || (msg_action_arg > 0 && !one_msg_action))
- ) ||
- (
- msg_action_arg > 0 &&
- (f.daemon_listen || queue_interval > 0 || list_options ||
- (checking && msg_action != MSG_LOAD) ||
- bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0)
- ) ||
- (
- (f.daemon_listen || queue_interval > 0) &&
- (sender_address != NULL || list_options || list_queue || checking ||
- bi_option)
- ) ||
- (
- f.daemon_listen && queue_interval == 0
- ) ||
- (
- f.inetd_wait_mode && queue_interval >= 0
- ) ||
- (
- list_options &&
- (checking || smtp_input || extract_recipients ||
- filter_test != FTEST_NONE || bi_option)
- ) ||
- (
- verify_address_mode &&
- (f.address_test_mode || smtp_input || extract_recipients ||
- filter_test != FTEST_NONE || bi_option)
- ) ||
- (
- f.address_test_mode && (smtp_input || extract_recipients ||
- filter_test != FTEST_NONE || bi_option)
- ) ||
- (
- smtp_input && (sender_address != NULL || filter_test != FTEST_NONE ||
- extract_recipients)
- ) ||
- (
- deliver_selectstring != NULL && queue_interval < 0
- ) ||
- (
- msg_action == MSG_LOAD &&
- (!expansion_test || expansion_test_message != NULL)
- )
+if ( ( (smtp_input || extract_recipients || recipients_arg < argc)
+ && ( f.daemon_listen || queue_interval >= 0 || bi_option
+ || test_retry_arg >= 0 || test_rewrite_arg >= 0
+ || filter_test != FTEST_NONE
+ || msg_action_arg > 0 && !one_msg_action
+ ) )
+ || ( msg_action_arg > 0
+ && ( f.daemon_listen || queue_interval > 0 || list_options
+ || checking && msg_action != MSG_LOAD
+ || bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0
+ ) )
+ || ( (f.daemon_listen || queue_interval > 0)
+ && ( sender_address || list_options || list_queue || checking
+ || bi_option
+ ) )
+ || f.daemon_listen && queue_interval == 0
+ || f.inetd_wait_mode && queue_interval >= 0
+ || ( list_options
+ && ( checking || smtp_input || extract_recipients
+ || filter_test != FTEST_NONE || bi_option
+ ) )
+ || ( verify_address_mode
+ && ( f.address_test_mode || smtp_input || extract_recipients
+ || filter_test != FTEST_NONE || bi_option
+ ) )
+ || ( f.address_test_mode
+ && ( smtp_input || extract_recipients || filter_test != FTEST_NONE
+ || bi_option
+ ) )
+ || ( smtp_input
+ && (sender_address || filter_test != FTEST_NONE || extract_recipients)
+ )
+ || deliver_selectstring && queue_interval < 0
+ || msg_action == MSG_LOAD && (!expansion_test || expansion_test_message)
)
exim_fail("exim: incompatible command-line options or arguments\n");
if (Uchdir(spool_directory) != 0)
{
- int dummy;
- (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
- dummy = /* quieten compiler */ Uchdir(spool_directory);
- dummy = dummy; /* yet more compiler quietening, sigh */
+ (void) directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
+ (void) Uchdir(spool_directory);
}
/* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
if (bi_option)
{
- (void)fclose(config_file);
- if (bi_command)
+ (void) fclose(config_file);
+ if (bi_command && *bi_command)
{
int i = 0;
uschar *argv[3];
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] ? argv[1] : US"");
+ DEBUG(D_exec) debug_printf("exec '%.256s' %s%.256s%s\n", argv[0],
+ argv[1] ? "'" : "", argv[1] ? argv[1] : US"", argv[1] ? "'" : "");
execv(CS argv[0], (char *const *)argv);
- exim_fail("exim: exec failed: %s\n", strerror(errno));
+ exim_fail("exim: exec '%s' failed: %s\n", argv[0], strerror(errno));
}
else
{
|| 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\n", debugset ? " debugging" : "");
}
/* If the real user is not root or the exim uid, the argument for passing
one that supplied an input message, or we are using a patched exim for
regression testing. */
-if (real_uid != root_uid && real_uid != exim_uid &&
- (continue_hostname != NULL ||
- (f.dont_deliver &&
- (queue_interval >= 0 || f.daemon_listen || msg_action_arg > 0)
- )) && !f.running_in_test_harness)
+if ( real_uid != root_uid && real_uid != exim_uid
+ && ( continue_hostname
+ || ( f.dont_deliver
+ && (queue_interval >= 0 || f.daemon_listen || msg_action_arg > 0)
+ ) )
+ && !f.running_in_test_harness
+ )
exim_fail("exim: Permission denied\n");
/* If the caller is not trusted, certain arguments are ignored when running for
else
{
- if (sender_host_address != NULL)
+ if (sender_host_address)
sender_host_port = check_port(sender_host_address);
- if (interface_address != NULL)
+ if (interface_address)
interface_port = check_port(interface_address);
}
situation (controlled by the TRUE below), in order to be as close as possible
to the state Exim usually runs in. */
-if (!unprivileged && /* originally had root AND */
- !removed_privilege && /* still got root AND */
- !f.daemon_listen && /* not starting the daemon */
- queue_interval <= 0 && /* (either kind of daemon) */
- ( /* AND EITHER */
- deliver_drop_privilege || /* requested unprivileged */
- ( /* OR */
- queue_interval < 0 && /* not running the queue */
- (msg_action_arg < 0 || /* and */
- msg_action != MSG_DELIVER) && /* not delivering and */
- (!checking || !f.address_test_mode) /* not address checking */
- ) ) )
+if ( !unprivileged /* originally had root AND */
+ && !removed_privilege /* still got root AND */
+ && !f.daemon_listen /* not starting the daemon */
+ && queue_interval <= 0 /* (either kind of daemon) */
+ && ( /* AND EITHER */
+ deliver_drop_privilege /* requested unprivileged */
+ || ( /* OR */
+ queue_interval < 0 /* not running the queue */
+ && ( msg_action_arg < 0 /* and */
+ || msg_action != MSG_DELIVER /* not delivering */
+ ) /* and */
+ && (!checking || !f.address_test_mode) /* not address checking */
+ && !rcpt_verify_quota /* and not quota checking */
+ ) ) )
exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed");
/* When we are retaining a privileged uid, we still change to the exim gid. */
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 */
#ifdef WITH_CONTENT_SCAN
int result;
set_process_info("scanning file for malware");
- result = malware_in_file(malware_test_file);
- if (result == FAIL)
+ if ((result = malware_in_file(malware_test_file)) == FAIL)
{
printf("No malware found.\n");
exit(EXIT_SUCCESS);
#endif
}
+/* Handle a request to check quota */
+if (rcpt_verify_quota)
+ if (real_uid != root_uid && real_uid != exim_uid)
+ exim_fail("exim: Permission denied\n");
+ else if (recipients_arg >= argc)
+ exim_fail("exim: missing recipient for quota check\n");
+ else
+ {
+ verify_quota(argv[recipients_arg]);
+ exim_exit(EXIT_SUCCESS);
+ }
+
/* 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
if (test_retry_arg >= argc)
{
printf("-brt needs a domain or address argument\n");
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
s1 = argv[test_retry_arg++];
s2 = NULL;
printf("\n");
}
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(EXIT_SUCCESS);
}
/* Handle a request to list one or more configuration options */
else
fail = !readconf_print(argv[i], NULL, flag_n);
}
- exim_exit(fail ? EXIT_FAILURE : EXIT_SUCCESS, US"main");
+ exim_exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
}
if (list_config)
{
set_process_info("listing config");
exim_exit(readconf_print(US"config", NULL, flag_n)
- ? EXIT_SUCCESS : EXIT_FAILURE, US"main");
+ ? EXIT_SUCCESS : EXIT_FAILURE);
}
if (prod_requires_admin && !f.admin_user)
{
fprintf(stderr, "exim: Permission denied\n");
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
set_process_info("delivering specified messages");
if (deliver_give_up) forced_delivery = f.deliver_force_thaw = TRUE;
that runs into a later copy into the untainted global message_id[] */
if (i == argc - 1)
(void)deliver_message(argv[i], forced_delivery, deliver_give_up);
- else if ((pid = fork()) == 0)
+ else if ((pid = exim_fork(US"cmdline-delivery")) == 0)
{
(void)deliver_message(argv[i], forced_delivery, deliver_give_up);
- exim_underbar_exit(EXIT_SUCCESS, US"cmdline-delivery");
+ exim_underbar_exit(EXIT_SUCCESS);
}
else if (pid < 0)
{
fprintf(stderr, "failed to fork delivery process for %s: %s\n", argv[i],
strerror(errno));
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
else wait(&status);
}
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(EXIT_SUCCESS);
}
else
set_process_info("running the queue (single queue run)");
queue_run(start_queue_run_id, stop_queue_run_id, FALSE);
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(EXIT_SUCCESS);
}
configuration specifies something to use. When running in the test harness,
any setting of unknown_login overrides the actual name. */
-if (originator_login == NULL || f.running_in_test_harness)
+if (!originator_login || f.running_in_test_harness)
{
- if (unknown_login != NULL)
+ if (unknown_login)
{
originator_login = expand_string(unknown_login);
- if (originator_name == NULL && unknown_username != NULL)
+ if (!originator_name && unknown_username)
originator_name = expand_string(unknown_username);
- if (originator_name == NULL) originator_name = US"";
+ if (!originator_name) originator_name = US"";
}
- if (originator_login == NULL)
+ if (!originator_login)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to get user name for uid %d",
(int)real_uid);
}
/* 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 = US 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
if (test_rewrite_arg >= argc)
{
printf("-brw needs an address argument\n");
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
rewrite_test(argv[test_rewrite_arg]);
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(EXIT_SUCCESS);
}
/* A locally-supplied message is considered to be coming from a local user
sender, or if a sender other than <> is set, override with the originator's
login (which will get qualified below), except when checking things. */
- if (sender_address == NULL /* No sender_address set */
- || /* OR */
+ if ( !sender_address /* No sender_address set */
+ || /* OR */
(sender_address[0] != 0 && /* Non-empty sender address, AND */
!checking)) /* Not running tests, including filter tests */
{
}
if (recipients_arg < argc)
- {
while (recipients_arg < argc)
{
/* Supplied addresses are tainted since they come from a user */
while (*++s == ',' || isspace(*s)) ;
}
}
- }
else for (;;)
{
}
route_tidyup();
- exim_exit(exit_value, US"main");
+ exim_exit(exit_value);
}
/* Handle expansion checking. Either expand items on the command line, or read
deliver_datafile = -1;
}
- exim_exit(EXIT_SUCCESS, US"main: expansion test");
+ exim_exit(EXIT_SUCCESS);
}
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();
}
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(EXIT_SUCCESS);
}
if (!smtp_start_session())
{
mac_smtp_fflush();
- exim_exit(EXIT_SUCCESS, US"smtp_start toplevel");
+ exim_exit(EXIT_SUCCESS);
}
}
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
cancel_cutthrough_connection(TRUE, US"receive dropped");
if (more) goto moreloop;
smtp_log_no_mail(); /* Log no mail if configured */
- exim_exit(EXIT_FAILURE, US"receive toplevel");
+ exim_exit(EXIT_FAILURE);
}
}
else
{
cancel_cutthrough_connection(TRUE, US"message setup dropped");
smtp_log_no_mail(); /* Log no mail if configured */
- exim_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS, US"msg setup toplevel");
+ exim_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
}
}
if (error_handling == ERRORS_STDERR)
{
fprintf(stderr, "exim: too many recipients\n");
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
else
return
{
fprintf(stderr, "exim: bad recipient address \"%s\": %s\n",
string_printing(list[i]), errmess);
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
else
{
for real; when reading the headers of a message for filter testing,
it is TRUE if the headers were terminated by '.' and FALSE otherwise. */
- if (message_id[0] == 0) exim_exit(EXIT_FAILURE, US"main");
+ if (message_id[0] == 0) exim_exit(EXIT_FAILURE);
} /* Non-SMTP message reception */
/* If this is a filter testing run, there are headers in store, but
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 ? ftest_localpart : originator_login;
deliver_localpart_orig = deliver_localpart;
deliver_localpart_prefix = ftest_prefix;
deliver_localpart_suffix = 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 */
{
DEBUG(D_receive) debug_printf("chdir(\"/\") failed\n");
- exim_exit(EXIT_FAILURE, US"main");
+ exim_exit(EXIT_FAILURE);
}
/* Now we run either a system filter test, or a user filter test, or both.
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, US"main");
+ 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, US"main");
+ exim_exit(EXIT_FAILURE);
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(EXIT_SUCCESS);
}
/* Else act on the result of message reception. We should not get here unless
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. */
pid_t pid;
search_tidyup();
- if ((pid = fork()) == 0)
+ if ((pid = exim_fork(US"local-accept-delivery")) == 0)
{
int rc;
close_unwanted(); /* Close unwanted file descriptors and TLS */
rc = deliver_message(message_id, FALSE, FALSE);
search_tidyup();
exim_underbar_exit(!mua_wrapper || rc == DELIVER_MUA_SUCCEEDED
- ? EXIT_SUCCESS : EXIT_FAILURE, US"cmdline-delivery");
+ ? EXIT_SUCCESS : EXIT_FAILURE);
}
if (pid < 0)
log_write(0, LOG_MAIN|LOG_PANIC,
"process %d crashed with signal %d while delivering %s",
(int)pid, status & 0x00ff, message_id);
- if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE, US"main");
+ if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE);
}
}
}
#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;
store_reset(reset_point);
}
-exim_exit(EXIT_SUCCESS, US"main"); /* Never returns */
+exim_exit(EXIT_SUCCESS); /* Never returns */
return 0; /* To stop compiler warning */
}