X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Freadconf.c;h=f21ce4d04b9ad307b007e0b2f98f03b52ddbe34c;hb=9d727701a16bf4a93b136fe01e1bf2e5996c96ee;hp=42bb5afe51599f71af847077592375e57ccaec62;hpb=f9ba5e2255cf18092750fffacb6a9603571a2be5;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/readconf.c b/src/src/readconf.c index 42bb5afe5..f21ce4d04 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -15,6 +15,9 @@ implementation of the conditional .ifdef etc. */ # include "macro_predef.h" #endif +#define READCONF_DEBUG if (FALSE) /* Change to TRUE to enable */ + + static uschar * syslog_facility_str; static void fn_smtp_receive_timeout(const uschar *, const uschar *); @@ -123,6 +126,7 @@ static optionlist optionlist_config[] = { #endif { "dns_again_means_nonexist", opt_stringptr, &dns_again_means_nonexist }, { "dns_check_names_pattern", opt_stringptr, &check_dns_names_pattern }, + { "dns_cname_loops", opt_int, &dns_cname_loops }, { "dns_csa_search_limit", opt_int, &dns_csa_search_limit }, { "dns_csa_use_reverse", opt_bool, &dns_csa_use_reverse }, { "dns_dnssec_ok", opt_int, &dns_dnssec_ok }, @@ -195,7 +199,9 @@ static optionlist optionlist_config[] = { { "local_from_prefix", opt_stringptr, &local_from_prefix }, { "local_from_suffix", opt_stringptr, &local_from_suffix }, { "local_interfaces", opt_stringptr, &local_interfaces }, +#ifdef HAVE_LOCAL_SCAN { "local_scan_timeout", opt_time, &local_scan_timeout }, +#endif { "local_sender_retain", opt_bool, &local_sender_retain }, { "localhost_number", opt_stringptr, &host_number_string }, { "log_file_path", opt_stringptr, &log_file_path }, @@ -234,6 +240,10 @@ static optionlist optionlist_config[] = { #endif { "pid_file_path", opt_stringptr, &pid_file_path }, { "pipelining_advertise_hosts", opt_stringptr, &pipelining_advertise_hosts }, +#ifdef EXPERIMENTAL_PIPE_CONNECT + { "pipelining_connect_advertise_hosts", opt_stringptr, + &pipe_connect_advertise_hosts }, +#endif #ifndef DISABLE_PRDR { "prdr_enable", opt_bool, &prdr_enable }, #endif @@ -345,6 +355,9 @@ static optionlist optionlist_config[] = { { "timezone", opt_stringptr, &timezone_string }, { "tls_advertise_hosts", opt_stringptr, &tls_advertise_hosts }, #ifdef SUPPORT_TLS +# ifdef EXPERIMENTAL_REQUIRETLS + { "tls_advertise_requiretls", opt_stringptr, &tls_advertise_requiretls }, +# endif { "tls_certificate", opt_stringptr, &tls_certificate }, { "tls_crl", opt_stringptr, &tls_crl }, { "tls_dh_max_bits", opt_int, &tls_dh_max_bits }, @@ -403,6 +416,19 @@ for (ai = auths_available; ai->driver_name[0]; ai++) } } +void +options_logging(void) +{ +bit_table * bp; +uschar buf[64]; + +for (bp = log_options; bp < log_options + log_options_count; bp++) + { + spf(buf, sizeof(buf), US"_LOG_%T", bp->name); + builtin_macro_create(buf); + } +} + #else /*!MACRO_PREDEF*/ @@ -592,6 +618,40 @@ return US""; +/************************************************* +* Deal with an assignment to a macro * +*************************************************/ + +/* We have a new definition; append to the list. + +Args: + name Name of the macro; will be copied + val Expansion result for the macro; will be copied +*/ + +macro_item * +macro_create(const uschar * name, const uschar * val, BOOL command_line) +{ +macro_item * m = store_get(sizeof(macro_item)); + +READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); +m->next = NULL; +m->command_line = command_line; +m->namelen = Ustrlen(name); +m->replen = Ustrlen(val); +m->name = string_copy(name); +m->replacement = string_copy(val); +if (mlast) + mlast->next = m; +else + macros = m; +mlast = m; +if (!macros_user) + macros_user = m; +return m; +} + + /* This function is called when a line that starts with an upper case letter is encountered. The argument "line" should contain a complete logical line, and start with the first letter of the macro name. The macro name and the @@ -642,37 +702,53 @@ while (isspace(*s)) s++; just skip this definition. It's an error to attempt to redefine a macro without redef set to TRUE, or to redefine a macro when it hasn't been defined earlier. It is also an error to define a macro whose name begins with the name of a -previously defined macro. +previously defined macro. This is the requirement that make using a tree +for macros hard; we must check all macros for the substring. Perhaps a +sorted list, and a bsearch, would work? Note: it is documented that the other way round works. */ -if ((m = macro_search_prefix(name))) +for (m = macros; m; m = m->next) { - if (m->namelen < namelen) /* substring match */ + if (Ustrcmp(m->name, name) == 0) { - log_write(0, LOG_CONFIG|LOG_PANIC, "\"%s\" cannot be defined as " - "a macro because previously defined macro \"%s\" is a substring", - name, m->tnode.name); - return FALSE; + if (!m->command_line && !redef) + { + log_write(0, LOG_CONFIG|LOG_PANIC, "macro \"%s\" is already " + "defined (use \"==\" if you want to redefine it)", name); + return FALSE; + } + break; } - /* exact match */ - if (!m->command_line && !redef) + + if (m->namelen < namelen && Ustrstr(name, m->name) != NULL) { - log_write(0, LOG_CONFIG|LOG_PANIC, "macro \"%s\" is already " - "defined (use \"==\" if you want to redefine it", name); + log_write(0, LOG_CONFIG|LOG_PANIC, "\"%s\" cannot be defined as " + "a macro because previously defined macro \"%s\" is a substring", + name, m->name); return FALSE; } - if (m->command_line) /* overriding cmdline definition */ - return TRUE; + /* We cannot have this test, because it is documented that a substring + macro is permitted (there is even an example). + * + * if (m->namelen > namelen && Ustrstr(m->name, name) != NULL) + * log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as " + * "a macro because it is a substring of previously defined macro \"%s\"", + * name, m->name); + */ } +/* Check for an overriding command-line definition. */ + +if (m && m->command_line) return TRUE; + /* Redefinition must refer to an existing macro. */ if (redef) if (m) { m->replen = Ustrlen(s); - m->tnode.data.ptr = string_copy(s); + m->replacement = string_copy(s); } else { @@ -693,7 +769,7 @@ return TRUE; /* Process line for macros. The line is in big_buffer starting at offset len. Expand big_buffer if needed. Handle definitions of new macros, and -imacro expansions, rewriting the line in thw buffer. +macro expansions, rewriting the line in the buffer. Arguments: len Offset in buffer of start of line @@ -708,6 +784,7 @@ macros_expand(int len, int * newlen, BOOL * macro_found) { uschar * ss = big_buffer + len; uschar * s; +macro_item * m; /* Find the true start of the physical line - leading spaces are always ignored. */ @@ -728,52 +805,61 @@ if (len == 0 && isupper(*s)) if (*s != '=') s = ss; /* Not a macro definition */ } -/* Scan the line (from after XXX= if present), replacing any macros. Rescan -after replacement for any later-defined macros. */ +/* Skip leading chars which cannot start a macro name, to avoid multiple +pointless rescans in Ustrstr calls. */ + +while (*s && !isupper(*s) && !(*s == '_' && isupper(s[1]))) s++; + +/* For each defined macro, scan the line (from after XXX= if present), +replacing all occurrences of the macro. */ *macro_found = FALSE; -while (*s) +if (*s) for (m = *s == '_' ? macros : macros_user; m; m = m->next) { - if (isupper(*s) || *s == '_' && isupper(s[1])) - { - macro_item * m; - unsigned mnum = 0; + uschar * p, *pp; + uschar * t; - while ((m = macro_search_largest_prefix(s)) && m->m_number > mnum) - { - uschar * pp; - int moveby; + while (*s && !isupper(*s) && !(*s == '_' && isupper(s[1]))) s++; + if (!*s) break; - /* Expand the buffer if necessary */ + t = s; + while ((p = Ustrstr(t, m->name)) != NULL) + { + int moveby; - while (*newlen - m->namelen + m->replen + 1 > big_buffer_size) - { - int newsize = big_buffer_size + BIG_BUFFER_SIZE; - uschar *newbuffer = store_malloc(newsize); - memcpy(newbuffer, big_buffer, *newlen + 1); - s = newbuffer + (s - big_buffer); - ss = newbuffer + (ss - big_buffer); - big_buffer_size = newsize; - store_free(big_buffer); - big_buffer = newbuffer; - } + READCONF_DEBUG fprintf(stderr, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, + m->name, (int) Ustrlen(ss)-1, ss); + /* Expand the buffer if necessary */ + + while (*newlen - m->namelen + m->replen + 1 > big_buffer_size) + { + int newsize = big_buffer_size + BIG_BUFFER_SIZE; + uschar *newbuffer = store_malloc(newsize); + memcpy(newbuffer, big_buffer, *newlen + 1); + p = newbuffer + (p - big_buffer); + s = newbuffer + (s - big_buffer); + ss = newbuffer + (ss - big_buffer); + t = newbuffer + (t - big_buffer); + big_buffer_size = newsize; + store_free(big_buffer); + big_buffer = newbuffer; + } - /* Shuffle the remaining characters up or down in the buffer before - copying in the replacement text. Don't rescan the replacement for this - same macro. */ + /* Shuffle the remaining characters up or down in the buffer before + copying in the replacement text. Don't rescan the replacement for this + same macro. */ - pp = s + m->namelen; - if ((moveby = m->replen - m->namelen) != 0) - { - memmove(s + m->replen, pp, (big_buffer + *newlen) - pp + 1); - *newlen += moveby; - } - Ustrncpy(s, m->tnode.data.ptr, m->replen); - *macro_found = TRUE; - mnum = m->m_number; + pp = p + m->namelen; + if ((moveby = m->replen - m->namelen) != 0) + { + memmove(p + m->replen, pp, (big_buffer + *newlen) - pp + 1); + *newlen += moveby; } + Ustrncpy(p, m->replacement, m->replen); + t = p + m->replen; + while (*t && !isupper(*t) && !(*t == '_' && isupper(t[1]))) t++; + *macro_found = TRUE; } - s++; } /* An empty macro replacement at the start of a line could mean that ss no @@ -2059,80 +2145,77 @@ switch (type) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s", inttype, name); - if (errno != ERANGE) - if (tolower(*endptr) == 'k') - { - if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024) errno = ERANGE; - else lvalue *= 1024; - endptr++; - } - else if (tolower(*endptr) == 'm') - { - if (lvalue > INT_MAX/(1024*1024) || lvalue < INT_MIN/(1024*1024)) - errno = ERANGE; - else lvalue *= 1024*1024; - endptr++; - } - else if (tolower(*endptr) == 'g') - { - if (lvalue > INT_MAX/(1024*1024*1024) || lvalue < INT_MIN/(1024*1024*1024)) - errno = ERANGE; - else lvalue *= 1024*1024*1024; - endptr++; - } + if (errno != ERANGE && *endptr) + { + uschar * mp = US"GgMmKk\0"; /* YyZzEePpTtGgMmKk */ + + if ((mp = Ustrchr(mp, *endptr))) + { + endptr++; + do + { + if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024) + { + errno = ERANGE; + break; + } + lvalue *= 1024; + } + while (*(mp += 2)); + } + } if (errno == ERANGE || lvalue > INT_MAX || lvalue < INT_MIN) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "absolute value of integer \"%s\" is too large (overflow)", s); while (isspace(*endptr)) endptr++; - if (*endptr != 0) + if (*endptr) extra_chars_error(endptr, inttype, US"integer value for ", name); value = (int)lvalue; } - if (data_block == NULL) - *((int *)(ol->value)) = value; + if (data_block) + *(int *)(US data_block + (long int)ol->value) = value; else - *((int *)(US data_block + (long int)(ol->value))) = value; + *(int *)ol->value = value; break; - /* Integer held in K: again, allow octal and hex formats, and suffixes K, M - and G. */ - /*XXX consider moving to int_eximarith_t (but mind the overflow test 0415) */ + /* Integer held in K: again, allow octal and hex formats, and suffixes K, M, + G and T. */ case opt_Kint: { uschar *endptr; errno = 0; - value = strtol(CS s, CSS &endptr, intbase); + int_eximarith_t lvalue = strtol(CS s, CSS &endptr, intbase); if (endptr == s) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s", inttype, name); - if (errno != ERANGE) - if (tolower(*endptr) == 'g') - { - if (value > INT_MAX/(1024*1024) || value < INT_MIN/(1024*1024)) - errno = ERANGE; - else - value *= 1024*1024; - endptr++; - } - else if (tolower(*endptr) == 'm') - { - if (value > INT_MAX/1024 || value < INT_MIN/1024) - errno = ERANGE; - else - value *= 1024; - endptr++; - } - else if (tolower(*endptr) == 'k') - endptr++; + if (errno != ERANGE && *endptr) + { + uschar * mp = US"EePpTtGgMmKk\0"; /* YyZzEePpTtGgMmKk */ + + if ((mp = Ustrchr(mp, *endptr))) + { + endptr++; + do + { + if (lvalue > EXIM_ARITH_MAX/1024 || lvalue < EXIM_ARITH_MIN/1024) + { + errno = ERANGE; + break; + } + lvalue *= 1024; + } + while (*(mp += 2)); + } else - value = (value + 512)/1024; + lvalue = (lvalue + 512)/1024; + } if (errno == ERANGE) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "absolute value of integer \"%s\" is too large (overflow)", s); @@ -2140,13 +2223,13 @@ switch (type) while (isspace(*endptr)) endptr++; if (*endptr != 0) extra_chars_error(endptr, inttype, US"integer value for ", name); - } - if (data_block == NULL) - *((int *)(ol->value)) = value; - else - *((int *)(US data_block + (long int)(ol->value))) = value; - break; + if (data_block) + *(int_eximarith_t *)(US data_block + (long int)ol->value) = lvalue; + else + *(int_eximarith_t *)ol->value = lvalue; + break; + } /* Fixed-point number: held to 3 decimal places. */ @@ -2345,7 +2428,7 @@ if (!ol) /* Non-admin callers cannot see options that have been flagged secure by the "hide" prefix. */ -if (!admin_user && ol->type & opt_secure) +if (!f.admin_user && ol->type & opt_secure) { if (no_labels) printf("%s\n", hidden); @@ -2403,11 +2486,12 @@ switch(ol->type & opt_mask) case opt_Kint: { - int x = *((int *)value); + int_eximarith_t x = *((int_eximarith_t *)value); if (!no_labels) printf("%s = ", name); if (x == 0) printf("0\n"); - else if ((x & 1023) == 0) printf("%dM\n", x >> 10); - else printf("%dK\n", x); + else if ((x & ((1<<20)-1)) == 0) printf(PR_EXIM_ARITH "G\n", x >> 20); + else if ((x & ((1<<10)-1)) == 0) printf(PR_EXIM_ARITH "M\n", x >> 10); + else printf(PR_EXIM_ARITH "K\n", x); } break; @@ -2704,7 +2788,7 @@ if (!type) if (Ustrcmp(name, "config") == 0) { - print_config(admin_user, no_labels); + print_config(f.admin_user, no_labels); return TRUE; } @@ -2805,30 +2889,33 @@ else if (Ustrcmp(type, "macro") == 0) { /* People store passwords in macros and they were previously not available for printing. So we have an admin_users restriction. */ - if (!admin_user) + if (!f.admin_user) { fprintf(stderr, "exim: permission denied\n"); return FALSE; } - - if (name) - if ((m = macro_search(name))) - macro_print(m->tnode.name, m->tnode.data.ptr, (void *)(long)names_only); - else + for (m = macros; m; m = m->next) + if (!name || Ustrcmp(name, m->name) == 0) { - printf("%s %s not found\n", type, name); - return FALSE; + if (names_only) + printf("%s\n", CS m->name); + else if (no_labels) + printf("%s\n", CS m->replacement); + else + printf("%s=%s\n", CS m->name, CS m->replacement); + if (name) + return TRUE; } - else - tree_walk(tree_macros, macro_print, (void *)(long)names_only); + if (!name) return TRUE; - return TRUE; + printf("%s %s not found\n", type, name); + return FALSE; } if (names_only) { for (; d; d = d->next) printf("%s\n", CS d->name); - return TRUE;; + return TRUE; } /* Either search for a given driver, or print all of them */ @@ -2838,8 +2925,7 @@ for (; d; d = d->next) BOOL rc = FALSE; if (!name) printf("\n%s %s:\n", d->name, type); - else if (Ustrcmp(d->name, name) != 0) - continue; + else if (Ustrcmp(d->name, name) != 0) continue; for (ol = ol2; ol < ol2 + size; ol++) if (!(ol->type & opt_hidden)) @@ -3210,7 +3296,7 @@ if (Uchdir("/") < 0) /* Check the status of the file we have opened, if we have retained root privileges and the file isn't /dev/null (which *should* be 0666). */ -if (trusted_config && Ustrcmp(filename, US"/dev/null")) +if (f.trusted_config && Ustrcmp(filename, US"/dev/null")) { if (fstat(fileno(config_file), &statbuf) != 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s", @@ -4126,6 +4212,9 @@ static void auths_init(void) { auth_instance *au, *bu; +#ifdef EXPERIMENTAL_PIPE_CONNECT +int nauths = 0; +#endif readconf_driver_init(US"authenticator", (driver_instance **)(&auths), /* chain anchor */ @@ -4149,7 +4238,13 @@ for (au = auths; au; au = au->next) "(%s and %s) have the same public name (%s)", au->client ? US"client" : US"server", au->name, bu->name, au->public_name); +#ifdef EXPERIMENTAL_PIPE_CONNECT + nauths++; +#endif } +#ifdef EXPERIMENTAL_PIPE_CONNECT +f.smtp_in_early_pipe_no_auth = nauths > 16; +#endif } @@ -4336,7 +4431,7 @@ void readconf_save_config(const uschar *s) { save_config_line(string_sprintf("# Exim Configuration (%s)", - running_in_test_harness ? US"X" : s)); + f.running_in_test_harness ? US"X" : s)); } static void