X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/79d4bc3d95d75446a2d149ca35525f078a978027..e6d225ae6e6811d3c88dc201642a2127ff6c11bd:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 729114c1c..bda61909a 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -776,53 +776,53 @@ fprintf(f, "Support for:"); #endif fprintf(f, "\n"); -fprintf(f, "Lookups:"); -#ifdef LOOKUP_LSEARCH +fprintf(f, "Lookups (built-in):"); +#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 fprintf(f, " lsearch wildlsearch nwildlsearch iplsearch"); #endif -#ifdef LOOKUP_CDB +#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2 fprintf(f, " cdb"); #endif -#ifdef LOOKUP_DBM +#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2 fprintf(f, " dbm dbmnz"); #endif -#ifdef LOOKUP_DNSDB +#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2 fprintf(f, " dnsdb"); #endif -#ifdef LOOKUP_DSEARCH +#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2 fprintf(f, " dsearch"); #endif -#ifdef LOOKUP_IBASE +#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 fprintf(f, " ibase"); #endif -#ifdef LOOKUP_LDAP +#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 fprintf(f, " ldap ldapdn ldapm"); #endif -#ifdef LOOKUP_MYSQL +#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2 fprintf(f, " mysql"); #endif -#ifdef LOOKUP_NIS +#if defined(LOOKUP_NIS) && LOOKUP_NIS!=2 fprintf(f, " nis nis0"); #endif -#ifdef LOOKUP_NISPLUS +#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2 fprintf(f, " nisplus"); #endif -#ifdef LOOKUP_ORACLE +#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2 fprintf(f, " oracle"); #endif -#ifdef LOOKUP_PASSWD +#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2 fprintf(f, " passwd"); #endif -#ifdef LOOKUP_PGSQL +#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 fprintf(f, " pgsql"); #endif -#ifdef LOOKUP_SQLITE +#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 fprintf(f, " sqlite"); #endif -#ifdef LOOKUP_TESTDB +#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2 fprintf(f, " testdb"); #endif -#ifdef LOOKUP_WHOSON +#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2 fprintf(f, " whoson"); #endif fprintf(f, "\n"); @@ -1131,6 +1131,117 @@ exit(EXIT_FAILURE); +/************************************************* +* Validate that the macros given are okay * +*************************************************/ + +/* Typically, Exim will drop privileges if macros are supplied. In some +cases, we want to not do so. + +Arguments: none (macros is a global) +Returns: true if trusted, false otherwise +*/ + +static BOOL +macros_trusted(void) +{ +#ifdef WHITELIST_D_MACROS +macro_item *m; +uschar *whitelisted, *end, *p, **whites, **w; +int white_count, i, n; +size_t len; +BOOL prev_char_item, found; +#endif + +if (macros == NULL) + return TRUE; +#ifndef WHITELIST_D_MACROS +return FALSE; +#else + +/* We only trust -D overrides for some invoking users: +root, the exim run-time user, the optional config owner user. +I don't know why config-owner would be needed, but since they can own the +config files anyway, there's no security risk to letting them override -D. */ +if ( ! ((real_uid == root_uid) + || (real_uid == exim_uid) +#ifdef CONFIGURE_OWNER + || (real_uid == config_uid) +#endif + )) + { + debug_printf("macros_trusted rejecting macros for uid %d\n", (int) real_uid); + return FALSE; + } + +/* Get a list of macros which are whitelisted */ +whitelisted = string_copy_malloc(US WHITELIST_D_MACROS); +prev_char_item = FALSE; +white_count = 0; +for (p = whitelisted; *p != '\0'; ++p) + { + if (*p == ':' || isspace(*p)) + { + *p = '\0'; + if (prev_char_item) + ++white_count; + prev_char_item = FALSE; + continue; + } + if (!prev_char_item) + prev_char_item = TRUE; + } +end = p; +if (prev_char_item) + ++white_count; +if (!white_count) + return FALSE; +whites = store_malloc(sizeof(uschar *) * (white_count+1)); +for (p = whitelisted, i = 0; (p != end) && (i < white_count); ++p) + { + if (*p != '\0') + { + whites[i++] = p; + if (i == white_count) + break; + while (*p != '\0' && p < end) + ++p; + } + } +whites[i] = NULL; + +/* The list of macros should be very short. Accept the N*M complexity. */ +for (m = macros; m != NULL; m = m->next) + { + found = FALSE; + for (w = whites; *w; ++w) + if (Ustrcmp(*w, m->name) == 0) + { + found = TRUE; + break; + } + if (!found) + return FALSE; + if (m->replacement == NULL) + continue; + len = Ustrlen(m->replacement); + if (len == 0) + continue; + n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len, + 0, PCRE_EOPT, NULL, 0); + if (n < 0) + { + if (n != PCRE_ERROR_NOMATCH) + debug_printf("macros_trusted checking %s returned %d\n", m->name, n); + return FALSE; + } + } +debug_printf("macros_trusted overriden to true by whitelisting\n"); +return TRUE; +#endif +} + + /************************************************* * Entry point and high-level code * *************************************************/ @@ -1417,6 +1528,15 @@ regex_smtp_code = regex_must_compile(US"^\\d\\d\\d\\s(?:\\d\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\s)?", FALSE, TRUE); +#ifdef WHITELIST_D_MACROS +/* Precompile the regular expression used to filter the content of macros +given to -D for permissibility. */ + +regex_whitelisted_macro = + regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE); +#endif + + /* If the program is called as "mailq" treat it as equivalent to "exim -bp"; this seems to be a generally accepted convention, since one finds symbolic links called "mailq" in standard OS configurations. */ @@ -1851,13 +1971,17 @@ for (i = 1; i < argc; i++) #endif if (real_uid != root_uid) { - #ifdef TRUSTED_CONFIG_PREFIX_LIST + #ifdef TRUSTED_CONFIG_LIST - if (Ustrstr(argrest, "/../")) + if (real_uid != exim_uid + #ifdef CONFIGURE_OWNER + && real_uid != config_uid + #endif + ) trusted_config = FALSE; else { - FILE *trust_list = Ufopen(TRUSTED_CONFIG_PREFIX_LIST, "rb"); + FILE *trust_list = Ufopen(TRUSTED_CONFIG_LIST, "rb"); if (trust_list) { struct stat statbuf; @@ -1883,8 +2007,8 @@ for (i = 1; i < argc; i++) { /* Well, the trust list at least is up to scratch... */ void *reset_point = store_get(0); - uschar *trusted_prefixes[32]; - int nr_prefixes = 0; + uschar *trusted_configs[32]; + int nr_configs = 0; int i = 0; while (Ufgets(big_buffer, big_buffer_size, trust_list)) @@ -1897,13 +2021,13 @@ for (i = 1; i < argc; i++) nl = Ustrchr(start, '\n'); if (nl) *nl = 0; - trusted_prefixes[nr_prefixes++] = string_copy(start); - if (nr_prefixes == 32) + trusted_configs[nr_configs++] = string_copy(start); + if (nr_configs == 32) break; } fclose(trust_list); - if (nr_prefixes) + if (nr_configs) { int sep = 0; uschar *list = argrest; @@ -1911,14 +2035,12 @@ for (i = 1; i < argc; i++) while (trusted_config && (filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) != NULL) { - for (i=0; i < nr_prefixes; i++) + for (i=0; i < nr_configs; i++) { - int len = Ustrlen(trusted_prefixes[i]); - if (Ustrlen(filename) >= len && - Ustrncmp(filename, trusted_prefixes[i], len) == 0) + if (Ustrcmp(filename, trusted_configs[i]) == 0) break; } - if (i == nr_prefixes) + if (i == nr_configs) { trusted_config = FALSE; break; @@ -3145,7 +3267,8 @@ values (such as the path name). If running in the test harness, pretend that configuration file changes and macro definitions haven't happened. */ if (( /* EITHER */ - (!trusted_config || macros != NULL) && /* Config changed, and */ + (!trusted_config || /* Config changed, or */ + !macros_trusted()) && /* impermissible macros and */ real_uid != root_uid && /* Not root, and */ !running_in_test_harness /* Not fudged */ ) || /* OR */ @@ -3362,7 +3485,7 @@ if (removed_privilege && (!trusted_config || macros != NULL) && else log_write(0, LOG_MAIN|LOG_PANIC, "exim user lost privilege for using %s option", - (int)exim_uid, trusted_config? "-D" : "-C"); + trusted_config? "-D" : "-C"); } /* Start up Perl interpreter if Perl support is configured and there is a @@ -3387,6 +3510,10 @@ if (opt_perl_at_start && opt_perl_startup != NULL) } #endif /* EXIM_PERL */ +/* Initialise lookup_list */ +extern void init_lookup_list(void); +init_lookup_list(); + /* Log the arguments of the call if the configuration file said so. This is a debugging feature for finding out what arguments certain MUAs actually use. Don't attempt it if logging is disabled, or if listing variables or if