* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* 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 */
#endif
extern void init_lookup_list(void);
+extern void init_misc_mod_list(void);
static void *
function_store_malloc(PCRE2_SIZE size, void * tag)
{
+if (size > INT_MAX)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request");
return store_malloc((int)size);
}
static void *
function_store_get(PCRE2_SIZE size, void * tag)
{
+if (size > INT_MAX)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "excessive memory alloc request");
return store_get((int)size, GET_UNTAINTED); /* loses track of taint */
}
static void
function_store_nullfree(void * block, void * tag)
{
+/* We cannot free memory allocated using store_get() */
}
static void
term_handler(int sig)
{
-exit(1);
+exim_exit(EXIT_FAILURE);
}
log_write(0, LOG_MAIN|LOG_PANIC, "backtrace");
log_write(0, LOG_MAIN|LOG_PANIC, "---");
+
+/* This function is officially not callable from a signal handler, as it
+calls malloc() for the returned data. However, it seems to work - and we
+know we're going on to crash anyway - so just hold our noses and do it.
+A alternative might be backtrace_symbols_fd(). */
+
if ((ss = backtrace_symbols(buf, nptrs)))
{
for (int i = 0; i < nptrs; i++)
#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);
if (fd < 0) return;
-(void)write(fd, process_info, process_info_len);
+if (write(fd, process_info, process_info_len) != 0) ;
(void)close(fd);
}
/* fail if a length is too long */
static inline void
-exim_len_fail_toolong(int itemlen, int maxlen, const char *description)
+exim_len_fail_toolong(int itemlen, int maxlen, const char * description)
{
if (itemlen <= maxlen)
return;
/* only pass through the string item back to the caller if it's short enough */
static inline const uschar *
-exim_str_fail_toolong(const uschar *item, int maxlen, const char *description)
+exim_str_fail_toolong(const uschar * item, int maxlen, const char * description)
{
+if (!item)
+ exim_fail("exim: bad item for: %s\n", description);
exim_len_fail_toolong(Ustrlen(item), maxlen, description);
return item;
}
+/* as above, copying as tainted */
+static inline const uschar *
+exim_arg_copy(const uschar * item, int maxlen, const char * description)
+{
+return string_copy_taint(exim_str_fail_toolong(item, maxlen, description),
+ GET_TAINTED);
+}
+
/* exim_chown_failure() called from exim_chown()/exim_fchown() on failure
of chown()/fchown(). See src/functions.h for more explanation */
int
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
}
+/* Bump the index for argv, checking for overflow,
+and return the argument. */
+
+static const uschar *
+next_argv(const uschar ** argv, int * pi, int argc, const uschar * where)
+{
+int i = *pi;
+if (++i >= argc) exim_fail("exim: bad item for: %s\n", where);
+return argv[*pi = i];
+}
+
+
/*************************************************
* Extract port from host address *
*************************************************/
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.
DEBUG(D_any) {} else g = show_db_version(g);
g = string_cat(g, US"Support for:");
+#ifdef WITH_CONTENT_SCAN
+ g = string_cat(g, US" Content_Scanning");
+#endif
+#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
+#ifdef EXPAND_DLFUNC
+ g = string_cat(g, US" Expand_dlfunc");
+#endif
#if HAVE_ICONV
g = string_cat(g, US" iconv()");
#endif
#if HAVE_IPV6
g = string_cat(g, US" IPv6");
#endif
-#ifdef HAVE_SETCLASSRESOURCES
- g = string_cat(g, US" use_setclassresources");
-#endif
#ifdef SUPPORT_PAM
g = string_cat(g, US" PAM");
#endif
#ifdef EXIM_PERL
g = string_cat(g, US" Perl");
#endif
-#ifdef EXPAND_DLFUNC
- g = string_cat(g, US" Expand_dlfunc");
-#endif
-#ifdef USE_TCP_WRAPPERS
- g = string_cat(g, US" TCPwrappers");
-#endif
#ifdef USE_GNUTLS
g = string_cat(g, US" GnuTLS");
#endif
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+ g = string_cat(g, US" move_frozen_messages");
+#endif
#ifdef USE_OPENSSL
g = string_cat(g, US" OpenSSL");
#endif
+#if defined(CYRUS_PWCHECK_SOCKET)
+ g = string_cat(g, US" pwcheck");
+#endif
+#if defined(RADIUS_CONFIG_FILE)
+ g = string_cat(g, US" radius");
+#endif
#ifndef DISABLE_TLS_RESUME
g = string_cat(g, US" TLS_resume");
#endif
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
g = string_cat(g, US" translate_ip_address");
#endif
-#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
- g = string_cat(g, US" move_frozen_messages");
+#ifdef USE_TCP_WRAPPERS
+ g = string_cat(g, US" TCPwrappers");
#endif
-#ifdef WITH_CONTENT_SCAN
- g = string_cat(g, US" Content_Scanning");
+#ifdef HAVE_SETCLASSRESOURCES
+ g = string_cat(g, US" use_setclassresources");
#endif
#ifdef SUPPORT_DANE
g = string_cat(g, US" DANE");
#ifndef DISABLE_DNSSEC
g = string_cat(g, US" DNSSEC");
#endif
+#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
#ifdef EXPERIMENTAL_DSN_INFO
g = string_cat(g, US" Experimental_DSN_info");
#endif
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
- g = string_cat(g, US" Experimental_ESMTP_Limits");
-#endif
#ifdef EXPERIMENTAL_QUEUEFILE
g = string_cat(g, US" Experimental_QUEUEFILE");
#endif
-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");
+#ifdef EXPERIMENTAL_XCLIENT
+ g = string_cat(g, US" Experimental_XCLIENT");
#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);
# ifdef __VERSION__
g = string_fmt_append(g, "Compiler: GCC [%s]\n", __VERSION__);
# else
- g = string_fmt_append(g, "Compiler: GCC [%s]\n", "? unknown version ?";
+ g = string_fmt_append(g, "Compiler: GCC [%s]\n", "? unknown version ?");
# endif
#else
g = string_cat(g, US"Compiler: <unknown>\n");
gnu_get_libc_version());
#endif
-g = show_db_version(g);
+ g = show_db_version(g);
#ifndef DISABLE_TLS
g = tls_version_report(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() */
-for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi)
- if (authi->version_report)
- g = (*authi->version_report)(g);
+ show_string(is_stdout, g);
+ g = NULL;
+
+ 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
#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);
);
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);
Returns: the local part, quoted if necessary
*/
-uschar *
-local_part_quote(uschar *lpart)
+const uschar *
+local_part_quote(const uschar * lpart)
{
BOOL needs_quote = FALSE;
gstring * g;
-for (uschar * t = lpart; !needs_quote && *t != 0; t++)
- {
+for (const uschar * t = lpart; !needs_quote && *t; t++)
needs_quote = !isalnum(*t) && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL &&
(*t != '.' || t == lpart || t[1] == 0);
- }
if (!needs_quote) return lpart;
for (;;)
{
- uschar *nq = US Ustrpbrk(lpart, "\\\"");
- if (nq == NULL)
+ uschar * nq = US Ustrpbrk(lpart, "\\\"");
+ if (!nq)
{
g = string_cat(g, lpart);
break;
*/
static void
-exim_usage(uschar *progname)
+exim_usage(const uschar * progname)
{
/* Handle specific program invocation variants */
(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);
memset(qrunners, 0, sizeof(qrunner)); /* default queue, zero interval */
qrunners->next_tick = time(NULL); /* run right away */
qrunners->run_max = 1;
+return qrunners;
}
*/
int
-main(int argc, char **cargv)
+main(int argc, char ** cargv)
{
-uschar **argv = USS cargv;
+const uschar ** argv = CUSS cargv;
int arg_receive_timeout = -1;
int arg_smtp_receive_timeout = -1;
int arg_error_handling = error_handling;
int filter_ufd = -1;
int group_count;
int i, rv;
-int list_queue_option = 0;
+int list_queue_option = QL_BASIC;
int msg_action = 0;
int msg_action_arg = -1;
int namelen = argv[0] ? Ustrlen(argv[0]) : 0;
BOOL verify_as_sender = FALSE;
BOOL rcpt_verify_quota = FALSE;
BOOL version_printed = FALSE;
-uschar *alias_arg = NULL;
-uschar *called_as = US"";
-uschar *cmdline_syslog_name = NULL;
-uschar *start_queue_run_id = NULL;
-uschar *stop_queue_run_id = NULL;
-uschar *expansion_test_message = NULL;
-const uschar *ftest_domain = NULL;
-const uschar *ftest_localpart = NULL;
-const uschar *ftest_prefix = NULL;
-const uschar *ftest_suffix = NULL;
-uschar *log_oneline = NULL;
-uschar *malware_test_file = NULL;
-uschar *real_sender_address;
-uschar *originator_home = US"/";
+const uschar * alias_arg = NULL;
+const uschar * called_as = US"";
+const uschar * cmdline_syslog_name = NULL;
+const uschar * start_queue_run_id = NULL;
+const uschar * stop_queue_run_id = NULL;
+const uschar * expansion_test_message = NULL;
+const uschar * ftest_domain = NULL;
+const uschar * ftest_localpart = NULL;
+const uschar * ftest_prefix = NULL;
+const uschar * ftest_suffix = NULL;
+uschar * log_oneline = NULL;
+const uschar * malware_test_file = NULL;
+const uschar * real_sender_address;
+uschar * originator_home = US"/";
size_t sz;
struct passwd *pw;
using mac_ismsgid, which uses this. */
regex_ismsgid =
- regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", MCS_NOFLAGS, TRUE);
+ regex_must_compile(US"^(?:"
+ "[^\\W_]{" str(MESSAGE_ID_TIME_LEN) "}"
+ "-[^\\W_]{" str(MESSAGE_ID_PID_LEN) "}"
+ "-[^\\W_]{" str(MESSAGE_ID_SUBTIME_LEN) "}"
+ "|"
+ "(?:[^\\W_]{6}-){2}[^\\W_]{2}" /* old ID format */
+ ")$",
+ MCS_NOFLAGS, TRUE);
/* Precompile the regular expression that is used for matching an SMTP error
code, possibly extended, at the start of an error message. Note that the
for (i = 1; i < argc; i++)
{
BOOL badarg = FALSE;
- uschar * arg = argv[i];
- uschar * argrest;
+ const uschar * arg = argv[i];
+ const uschar * argrest;
uschar switchchar;
/* An argument not starting with '-' is the start of a recipients list;
/* sendmail uses -Ac and -Am to control which .cf file is used;
we ignore them. */
case 'A':
- if (!*argrest) { badarg = TRUE; break; }
- else
- {
- BOOL ignore = FALSE;
- switch (*argrest)
- {
- case 'c':
- case 'm':
- if (*(argrest + 1) == '\0')
- ignore = TRUE;
- break;
- }
- if (!ignore) badarg = TRUE;
- }
- break;
+ if (!*argrest) { badarg = TRUE; break; }
+ else
+ {
+ BOOL ignore = FALSE;
+ switch (*argrest)
+ {
+ case 'c':
+ case 'm':
+ if (*(argrest + 1) == '\0')
+ ignore = TRUE;
+ break;
+ }
+ if (!ignore) badarg = TRUE;
+ }
+ break;
+
+ /* -atrn <host> <domains> */
+ case 'a':
+ if (Ustrcmp(argrest, "trn") == 0)
+ if (i+2 < argc)
+ {
+ atrn_mode = US"C"; /* Customer mode */
+
+ /* The host could at this point have a port attached */
+ atrn_host = exim_arg_copy(argv[++i], EXIM_DOMAINNAME_MAX, "-atrn");
+ atrn_domains = exim_arg_copy(argv[++i], EXIM_DOMAINNAME_MAX*4,
+ "-atrn");
+ i++;
+ }
+ else
+ exim_fail("exim: host and domainlist expected after %s\n", argv[i]);
+ else badarg = TRUE;
+ break;
/* -Btype is a sendmail option for 7bit/8bit setting. Exim is 8-bit clean
so has no need of it. */
case 'B':
- if (!*argrest) i++; /* Skip over the type */
- break;
+ if (!*argrest) i++; /* Skip over the type */
+ break;
case 'b':
/* -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);
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,
case 'I':
if (Ustrlen(argrest) >= 1 && *argrest == ':')
{
- uschar *p = argrest+1;
+ const uschar * p = argrest+1;
info_flag = CMDINFO_HELP;
if (Ustrlen(p))
if (strcmpic(p, CUS"sieve") == 0)
}
if (*argrest == 'r')
- {
- list_queue_option = 8;
- argrest++;
- }
- else list_queue_option = 0;
+ list_queue_option = QL_UNSORTED, argrest++;
+ else
+ list_queue_option = QL_BASIC;
list_queue = TRUE;
/* -bpu: List the contents of the mail queue, top-level undelivered */
- else if (Ustrcmp(argrest, "u") == 0) list_queue_option += 1;
+ else if (Ustrcmp(argrest, "u") == 0) list_queue_option |= QL_UNDELIVERED_ONLY;
/* -bpa: List the contents of the mail queue, including all delivered */
- else if (Ustrcmp(argrest, "a") == 0) list_queue_option += 2;
+ else if (Ustrcmp(argrest, "a") == 0) list_queue_option |= QL_PLUS_GENERATED;
+
+ /* -bpi: List only message IDs */
+
+ else if (Ustrcmp(argrest, "i") == 0) list_queue_option |= QL_MSGID_ONLY;
/* Unknown after -bp[r] */
/* -bw: inetd wait mode, accept a listening socket as stdin */
case 'w':
- f.inetd_wait_mode = TRUE;
+ f.inetd_wait_mode = f.daemon_listen = f.daemon_scion = TRUE;
f.background_daemon = FALSE;
- f.daemon_listen = f.daemon_scion = TRUE;
if (*argrest)
if ((inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE)) <= 0)
exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
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;
#else
{
int ptr = 0;
- macro_item *m;
+ macro_item * m;
uschar name[24];
- uschar *s = argrest;
+ const uschar * s = argrest;
opt_D_used = TRUE;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
if (*s < 'A' || *s > 'Z')
exim_fail("exim: macro name set by -D must start with "
}
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)
if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
(void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f");
if (!*argrest)
- *(sender_address = store_get(1, GET_UNTAINTED)) = '\0'; /* Ensure writeable memory */
+ {
+ uschar * s = store_get(1, GET_UNTAINTED); /* Ensure writeable memory */
+ *s = '\0';
+ sender_address = s;
+ }
else
{
- uschar * temp = argrest + Ustrlen(argrest) - 1;
+ const uschar * temp = argrest + Ustrlen(argrest) - 1;
while (temp >= argrest && isspace(*temp)) temp--;
if (temp >= argrest && *temp == '.') f_end_dot = TRUE;
allow_domain_literals = TRUE;
case 'K': smtp_peer_options |= OPTION_CHUNKING; break;
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
/* -MCL: peer used LIMITS RCPTMAX and/or RCPTDOMAINMAX */
case 'L': if (++i < argc) continue_limit_mail = Uatoi(argv[i]);
else badarg = TRUE;
{
msg_action = MSG_SETQUEUE;
queue_name_dest = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"),
+ exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+ EXIM_DRIVERNAME_MAX, "-MG"),
GET_TAINTED);
}
else if (Ustrcmp(argrest, "mad") == 0) msg_action = MSG_MARK_ALL_DELIVERED;
/* -oB: Set a connection message max value for remote deliveries */
case 'B':
{
- uschar * p = argrest;
+ const uschar * p = argrest;
if (!*p)
if (i+1 < argc && isdigit((argv[i+1][0])))
p = argv[++i];
if (Ustrcmp(argrest, "a") == 0)
sender_host_address = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"),
- GET_TAINTED);
+ exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+ EXIM_IPADDR_MAX, "-oMa"), GET_TAINTED);
/* -oMaa: Set authenticator name */
else if (Ustrcmp(argrest, "aa") == 0)
sender_host_authenticated = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"),
- GET_TAINTED);
+ exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+ EXIM_DRIVERNAME_MAX, "-oMaa"), GET_TAINTED);
/* -oMas: setting authenticated sender */
else if (Ustrcmp(argrest, "as") == 0)
authenticated_sender = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
- GET_TAINTED);
+ exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+ EXIM_EMAILADDR_MAX, "-oMas"), GET_TAINTED);
/* -oMai: setting authenticated id */
else if (Ustrcmp(argrest, "ai") == 0)
authenticated_id = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMai"),
- GET_TAINTED);
+ exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+ EXIM_EMAILADDR_MAX, "-oMai"), GET_TAINTED);
/* -oMi: Set incoming interface address */
else if (Ustrcmp(argrest, "i") == 0)
interface_address = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"),
- GET_TAINTED);
+ exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+ EXIM_IPADDR_MAX, "-oMi"), GET_TAINTED);
/* -oMm: Message reference */
exim_fail("-oMm must be a valid message ID\n");
if (!f.trusted_config)
exim_fail("-oMm must be called by a trusted user/config\n");
- message_reference = argv[++i];
+ message_reference = next_argv(argv, &i, argc, arg);
}
/* -oMr: Received protocol */
if (received_protocol)
exim_fail("received_protocol is set already\n");
else
- received_protocol = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"),
- GET_TAINTED);
+ if (++i >= argc) badarg = TRUE;
+ else
+ received_protocol = string_copy_taint(
+ exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-oMr"),
+ GET_TAINTED);
/* -oMs: Set sender host name */
else if (Ustrcmp(argrest, "s") == 0)
- sender_host_name = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"),
- GET_TAINTED);
+ if (++i >= argc) badarg = TRUE;
+ else
+ sender_host_name = string_copy_taint(
+ exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-oMs"),
+ GET_TAINTED);
/* -oMt: Set sender ident */
else if (Ustrcmp(argrest, "t") == 0)
- {
- sender_ident_set = TRUE;
- sender_ident = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"),
- GET_TAINTED);
- }
+ if (++i >= argc) badarg = TRUE;
+ else
+ {
+ sender_ident_set = TRUE;
+ sender_ident = string_copy_taint(
+ exim_str_fail_toolong(argv[i], EXIM_IDENTUSER_MAX, "-oMt"),
+ GET_TAINTED);
+ }
/* Else a bad argument */
exim_fail("exim: only uid=%d or uid=%d can use -oP and -oPX "
"(uid=%d euid=%d | %d)\n",
root_uid, exim_uid, getuid(), geteuid(), real_uid);
- if (!*argrest) override_pid_file_path = argv[++i];
+ if (!*argrest)
+ if (++i < argc) override_pid_file_path = argv[i];
+ else badarg = TRUE;
else if (Ustrcmp(argrest, "X") == 0) delete_pid_file();
else badarg = TRUE;
break;
/* Limits: Is there a real limit we want here? 1024 is very arbitrary. */
case 'X':
- if (*argrest) badarg = TRUE;
+ if (*argrest || ++i >= argc) badarg = TRUE;
else override_local_interfaces = string_copy_taint(
- exim_str_fail_toolong(argv[++i], 1024, "-oX"),
- GET_TAINTED);
+ exim_str_fail_toolong(argv[i], 1024, "-oX"), GET_TAINTED);
break;
/* -oY: Override creation of daemon notifier socket */
which sets the host protocol and host name */
if (!*argrest)
- if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
+ argrest = next_argv(argv, &i, argc, arg);
if (*argrest)
{
else
{
- int intvl = readconf_readtime(*argrest ? argrest : argv[++i], 0, FALSE);
- if (intvl <= 0)
+ int intvl;
+ const uschar * s;
+
+ if (*argrest) s = argrest;
+ else if (++i < argc) { badarg = TRUE; break; }
+ else s = argv[i];
+
+ if ((intvl = readconf_readtime(s, 0, FALSE)) <= 0)
exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
for (qrunner * qq = qrunners; qq; qq = qq->next)
in all cases provided there are no further characters in this
argument. */
- alloc_onetime_qrunner();
+ if (!qrunners) alloc_onetime_qrunner();
qrunners->queue_2stage = f.queue_2stage;
if (*argrest)
for (int i = 0; i < nelem(rsopts); i++)
tested. Otherwise variability of clock ticks etc. cause problems. */
case 'T':
- if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0)
- fudged_queue_times = string_copy_taint(argv[++i], GET_TAINTED);
+ if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0 && ++i < argc)
+ fudged_queue_times = string_copy_taint(argv[i], GET_TAINTED);
else badarg = TRUE;
break;
if (usage_wanted) exim_usage(called_as);
/* Arguments have been processed. Check for incompatibilities. */
-if ( ( (smtp_input || extract_recipients || recipients_arg < argc)
+if ( (smtp_input || extract_recipients || recipients_arg < argc)
&& ( f.daemon_listen || qrunners || 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
+ )
+ || msg_action_arg > 0
&& ( f.daemon_listen || is_multiple_qrun() || list_options
|| checking && msg_action != MSG_LOAD
|| bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0
- ) )
- || ( (f.daemon_listen || is_multiple_qrun())
+ )
+ || (f.daemon_listen || is_multiple_qrun())
&& ( sender_address || list_options || list_queue || checking
|| bi_option
- ) )
+ )
|| f.daemon_listen && is_onetime_qrun()
|| f.inetd_wait_mode && qrunners
- || ( list_options
+ || list_options
&& ( checking || smtp_input || extract_recipients
|| filter_test != FTEST_NONE || bi_option
- ) )
- || ( verify_address_mode
+ )
+ || verify_address_mode
&& ( f.address_test_mode || smtp_input || extract_recipients
|| filter_test != FTEST_NONE || bi_option
- ) )
- || ( f.address_test_mode
+ )
+ || f.address_test_mode
&& ( smtp_input || extract_recipients || filter_test != FTEST_NONE
|| bi_option
- ) )
- || ( smtp_input
+ )
+ || smtp_input
&& (sender_address || filter_test != FTEST_NONE || extract_recipients)
- )
|| deliver_selectstring && !qrunners
|| msg_action == MSG_LOAD && (!expansion_test || expansion_test_message)
+ || atrn_mode
+ && ( f.daemon_listen || expansion_test || filter_test != FTEST_NONE
+ || checking /* || bi_option || info_stdout || receiving_message
+ || malware_test_file || list_queue || list_config || list_options
+ || version_printed || msg_action_arg > 0 || qrunners
+ */
+ )
)
exim_fail("exim: incompatible command-line options or arguments\n");
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
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;
}
if (Uchdir(spool_directory) != 0)
{
(void) directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
- (void) Uchdir(spool_directory);
+ if (Uchdir(spool_directory) < 0) ;
}
/* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
if (bi_command && *bi_command)
{
int i = 0;
- uschar *argv[3];
+ const uschar * argv[3];
argv[i++] = bi_command; /* nonexpanded option so assume untainted */
if (alias_arg) argv[i++] = alias_arg;
argv[i++] = NULL;
|| queue_name_dest && prod_requires_admin
|| debugset && !f.running_in_test_harness
)
- exim_fail("exim:%s permission denied\n", debugset ? " debugging" : "");
+ exim_fail("exim:%s permission denied; not admin\n",
+ debugset ? " debugging" : "");
}
/* If the real user is not root or the exim uid, the argument for passing
) )
&& !f.running_in_test_harness
)
- exim_fail("exim: Permission denied\n");
+ exim_fail("exim: Permission denied; not exim user or root\n");
/* If the caller is not trusted, certain arguments are ignored when running for
real, but are permitted when checking things (-be, -bv, -bt, -bh, -bf, -bF).
if (real_uid == root_uid || real_uid == exim_uid || interface_port < 1024)
{
+ if (mua_wrapper) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Input from "
+ "inetd is not supported when mua_wrapper is set");
f.is_inetd = TRUE;
sender_host_address = host_ntoa(-1, (struct sockaddr *)(&inetd_sock),
NULL, &sender_host_port);
- if (mua_wrapper) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Input from "
- "inetd is not supported when mua_wrapper is set");
}
else
exim_fail(
#ifdef LOAD_AVG_NEEDS_ROOT
if ( receiving_message
- && (queue_only_load >= 0 || (f.is_inetd && smtp_load_reserve >= 0)))
+ && (queue_only_load >= 0 || f.is_inetd && smtp_load_reserve >= 0))
load_average = OS_GETLOADAVG();
#endif
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);
#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 */
{
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 */
{
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
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
exim_fail("exim: missing recipient for quota check\n");
else
{
- verify_quota(argv[recipients_arg]);
+ verify_quota(US argv[recipients_arg]); /*XXX we lose track of const here */
exim_exit(EXIT_SUCCESS);
}
/* 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;
if (!originator_login || f.running_in_test_harness)
{
+ GET_OPTION("unknown_login");
if (unknown_login)
{
originator_login = expand_string(unknown_login);
(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
#endif
daemon_go();
+ /*NOTREACHED*/
}
/* If the sender ident has not been set (by a trusted caller) set it to
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)
(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);
/* 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 */
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
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
}
/* 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 */
"**** This is not for real!\n\n",
sender_host_address);
+ set_connection_id();
memset(sender_host_cache, 0, sizeof(sender_host_cache));
if (verify_check_host(&hosts_connection_nolog) == OK)
{
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;
verification test or info dump.
In the former case, show the configuration file name. */
-if (recipients_arg >= argc && !extract_recipients && !smtp_input)
+if ( recipients_arg >= argc && !extract_recipients
+ && !smtp_input && !atrn_mode)
{
if (version_printed)
{
exim_usage(called_as);
}
+/*XXX somewhere around here. Maybe earlier, but no later. ATRN customer */
+if (atrn_mode)
+ atrn_handle_customer();
+
/* If mua_wrapper is set, Exim is being used to turn an MUA that submits on the
standard input into an MUA that submits to a smarthost over TCP/IP. We know
logging being sent down the socket and make an identd call to get the
sender_ident. */
-else if (f.is_inetd)
+else if (f.is_inetd && !atrn_mode)
{
(void)fclose(stderr);
exim_nullstd(); /* Re-open to /dev/null */
(usually "connection refused: <reason>") and writing another one is
unnecessary clutter. */
+set_connection_id();
if (smtp_input)
{
smtp_in = stdin;
smtp_out = stdout;
+
memset(sender_host_cache, 0, sizeof(sender_host_cache));
if (verify_check_host(&hosts_connection_nolog) == OK)
{
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)
rmark reset_point = store_mark();
message_id[0] = 0;
- /* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP
+ /* Handle the SMTP case; call smtp_setup_msg() to deal with the initial SMTP
input and build the recipients list, before calling receive_msg() to read the
message proper. Whatever sender address is given in the SMTP transaction is
often ignored for local senders - we use the actual sender, which is normally
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;
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 */
else
{
- int rcount = 0;
- int count = argc - recipients_arg;
- uschar **list = argv + recipients_arg;
+ uschar * rme = expand_string(recipients_max);
+ int rcount = 0, count = argc - recipients_arg;
+ const uschar ** list = argv + recipients_arg;
+
+ recipients_max_expanded = atoi(CCS rme);
/* These options cannot be changed dynamically for non-SMTP messages */
int start, end, domain;
uschar * errmess;
/* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short.
- * We'll still want to cap it to something, just in case. */
+ We'll still want to cap it to something, just in case. */
uschar * s = string_copy_taint(
exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"),
GET_TAINTED);
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");
return
moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)?
errors_sender_rc : EXIT_FAILURE;
+ }
#ifdef SUPPORT_I18N
{
}
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",
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)));
}
}
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);
deliver_localpart_data = deliver_domain_data =
recipient_data = sender_data = NULL;
acl_var_m = NULL;
+ lookup_value = NULL; /* Can be set by ACL */
store_reset(reset_point);
}
/* End of exim.c */
+/* vi: aw ai sw=2
+*/