X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/3acf26c7e9012515ea2936d1d7aab67652049f46..d185889f47b9b27088e777f7d382295c51271586:/src/src/readconf.c diff --git a/src/src/readconf.c b/src/src/readconf.c index 6bcc50752..045b992a4 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -11,133 +11,12 @@ implementation of the conditional .ifdef etc. */ #include "exim.h" -extern char **environ; - -static void fn_smtp_receive_timeout(const uschar * name, const uschar * str); -static void save_config_line(const uschar* line); -static void save_config_position(const uschar *file, int line); -static void print_config(BOOL admin, BOOL terse); -static void readconf_options_auths(void); - - -#define CSTATE_STACK_SIZE 10 - - -/* Structure for chain (stack) of .included files */ - -typedef struct config_file_item { - struct config_file_item *next; - uschar *filename; - FILE *file; - int lineno; -} config_file_item; - -/* Structure for chain of configuration lines (-bP config) */ - -typedef struct config_line_item { - struct config_line_item *next; - uschar *line; -} config_line_item; - -static config_line_item* config_lines; - -/* Structure of table of conditional words and their state transitions */ - -typedef struct cond_item { - uschar *name; - int namelen; - int action1; - int action2; - int pushpop; -} cond_item; - -/* Structure of table of syslog facility names and values */ - -typedef struct syslog_fac_item { - uschar *name; - int value; -} syslog_fac_item; - -/* constants */ -static const char * const hidden = ""; - -/* Static variables */ - -static config_file_item *config_file_stack = NULL; /* For includes */ - -static uschar *syslog_facility_str = NULL; -static uschar next_section[24]; -static uschar time_buffer[24]; - -/* State variables for conditional loading (.ifdef / .else / .endif) */ - -static int cstate = 0; -static int cstate_stack_ptr = -1; -static int cstate_stack[CSTATE_STACK_SIZE]; - -/* Table of state transitions for handling conditional inclusions. There are -four possible state transitions: - - .ifdef true - .ifdef false - .elifdef true (or .else) - .elifdef false - -.endif just causes the previous cstate to be popped off the stack */ - -static int next_cstate[3][4] = - { - /* State 0: reading from file, or reading until next .else or .endif */ - { 0, 1, 2, 2 }, - /* State 1: condition failed, skipping until next .else or .endif */ - { 2, 2, 0, 1 }, - /* State 2: skipping until .endif */ - { 2, 2, 2, 2 }, - }; - -/* Table of conditionals and the states to set. For each name, there are four -values: the length of the name (to save computing it each time), the state to -set if a macro was found in the line, the state to set if a macro was not found -in the line, and a stack manipulation setting which is: - - -1 pull state value off the stack - 0 don't alter the stack - +1 push value onto stack, before setting new state -*/ - -static cond_item cond_list[] = { - { US"ifdef", 5, 0, 1, 1 }, - { US"ifndef", 6, 1, 0, 1 }, - { US"elifdef", 7, 2, 3, 0 }, - { US"elifndef", 8, 3, 2, 0 }, - { US"else", 4, 2, 2, 0 }, - { US"endif", 5, 0, 0, -1 } -}; - -static int cond_list_size = sizeof(cond_list)/sizeof(cond_item); - -/* Table of syslog facility names and their values */ - -static syslog_fac_item syslog_list[] = { - { US"mail", LOG_MAIL }, - { US"user", LOG_USER }, - { US"news", LOG_NEWS }, - { US"uucp", LOG_UUCP }, - { US"local0", LOG_LOCAL0 }, - { US"local1", LOG_LOCAL1 }, - { US"local2", LOG_LOCAL2 }, - { US"local3", LOG_LOCAL3 }, - { US"local4", LOG_LOCAL4 }, - { US"local5", LOG_LOCAL5 }, - { US"local6", LOG_LOCAL6 }, - { US"local7", LOG_LOCAL7 }, - { US"daemon", LOG_DAEMON } -}; - -static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item); - - +#ifdef MACRO_PREDEF +# include "macro_predef.h" +#endif +static uschar * syslog_facility_str; +static void fn_smtp_receive_timeout(const uschar *, const uschar *); /************************************************* * Main configuration options * @@ -214,6 +93,7 @@ static optionlist optionlist_config[] = { { "check_spool_inodes", opt_int, &check_spool_inodes }, { "check_spool_space", opt_Kint, &check_spool_space }, { "chunking_advertise_hosts", opt_stringptr, &chunking_advertise_hosts }, + { "commandline_checks_require_admin", opt_bool,&commandline_checks_require_admin }, { "daemon_smtp_port", opt_stringptr|opt_hidden, &daemon_smtp_port }, { "daemon_smtp_ports", opt_stringptr, &daemon_smtp_port }, { "daemon_startup_retries", opt_int, &daemon_startup_retries }, @@ -223,6 +103,7 @@ static optionlist optionlist_config[] = { { "dccifd_address", opt_stringptr, &dccifd_address }, { "dccifd_options", opt_stringptr, &dccifd_options }, #endif + { "debug_store", opt_bool, &debug_store }, { "delay_warning", opt_timelist, &delay_warning }, { "delay_warning_condition", opt_stringptr, &delay_warning_condition }, { "deliver_drop_privilege", opt_bool, &deliver_drop_privilege }, @@ -250,7 +131,7 @@ static optionlist optionlist_config[] = { { "dns_retry", opt_int, &dns_retry }, { "dns_trust_aa", opt_stringptr, &dns_trust_aa }, { "dns_use_edns0", opt_int, &dns_use_edns0 }, - /* This option is now a no-op, retained for compability */ + /* This option is now a no-op, retained for compatibility */ { "drop_cr", opt_bool, &drop_cr }, /*********************************************************/ { "dsn_advertise_hosts", opt_stringptr, &dsn_advertise_hosts }, @@ -428,6 +309,7 @@ static optionlist optionlist_config[] = { #endif { "split_spool_directory", opt_bool, &split_spool_directory }, { "spool_directory", opt_stringptr, &spool_directory }, + { "spool_wireformat", opt_bool, &spool_wireformat }, #ifdef LOOKUP_SQLITE { "sqlite_lock_timeout", opt_int, &sqlite_lock_timeout }, #endif @@ -445,6 +327,7 @@ static optionlist optionlist_config[] = { { "strip_trailing_dot", opt_bool, &strip_trailing_dot }, { "syslog_duplication", opt_bool, &syslog_duplication }, { "syslog_facility", opt_stringptr, &syslog_facility_str }, + { "syslog_pid", opt_bool, &syslog_pid }, { "syslog_processname", opt_stringptr, &syslog_processname }, { "syslog_timestamp", opt_bool, &syslog_timestamp }, { "system_filter", opt_stringptr, &system_filter }, @@ -492,6 +375,163 @@ static optionlist optionlist_config[] = { static int optionlist_config_size = nelem(optionlist_config); +#ifdef MACRO_PREDEF + +static void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {/*Dummy*/} + +void +options_main(void) +{ +options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN", NULL); +} + +void +options_auths(void) +{ +struct auth_info * ai; +uschar buf[64]; + +options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL); + +for (ai = auths_available; ai->driver_name[0]; ai++) + { + snprintf(buf, sizeof(buf), "_DRIVER_AUTHENTICATOR_%T", ai->driver_name); + builtin_macro_create(buf); + options_from_list(ai->options, (unsigned)*ai->options_count, US"AUTHENTICATOR", ai->driver_name); + } +} + + +#else /*!MACRO_PREDEF*/ + +extern char **environ; + +static void save_config_line(const uschar* line); +static void save_config_position(const uschar *file, int line); +static void print_config(BOOL admin, BOOL terse); + + +#define CSTATE_STACK_SIZE 10 + +const uschar *config_directory = NULL; + + +/* Structure for chain (stack) of .included files */ + +typedef struct config_file_item { + struct config_file_item *next; + const uschar *filename; + const uschar *directory; + FILE *file; + int lineno; +} config_file_item; + +/* Structure for chain of configuration lines (-bP config) */ + +typedef struct config_line_item { + struct config_line_item *next; + uschar *line; +} config_line_item; + +static config_line_item* config_lines; + +/* Structure of table of conditional words and their state transitions */ + +typedef struct cond_item { + uschar *name; + int namelen; + int action1; + int action2; + int pushpop; +} cond_item; + +/* Structure of table of syslog facility names and values */ + +typedef struct syslog_fac_item { + uschar *name; + int value; +} syslog_fac_item; + +/* constants */ +static const char * const hidden = ""; + +/* Static variables */ + +static config_file_item *config_file_stack = NULL; /* For includes */ + +static uschar *syslog_facility_str = NULL; +static uschar next_section[24]; +static uschar time_buffer[24]; + +/* State variables for conditional loading (.ifdef / .else / .endif) */ + +static int cstate = 0; +static int cstate_stack_ptr = -1; +static int cstate_stack[CSTATE_STACK_SIZE]; + +/* Table of state transitions for handling conditional inclusions. There are +four possible state transitions: + + .ifdef true + .ifdef false + .elifdef true (or .else) + .elifdef false + +.endif just causes the previous cstate to be popped off the stack */ + +static int next_cstate[3][4] = + { + /* State 0: reading from file, or reading until next .else or .endif */ + { 0, 1, 2, 2 }, + /* State 1: condition failed, skipping until next .else or .endif */ + { 2, 2, 0, 1 }, + /* State 2: skipping until .endif */ + { 2, 2, 2, 2 }, + }; + +/* Table of conditionals and the states to set. For each name, there are four +values: the length of the name (to save computing it each time), the state to +set if a macro was found in the line, the state to set if a macro was not found +in the line, and a stack manipulation setting which is: + + -1 pull state value off the stack + 0 don't alter the stack + +1 push value onto stack, before setting new state +*/ + +static cond_item cond_list[] = { + { US"ifdef", 5, 0, 1, 1 }, + { US"ifndef", 6, 1, 0, 1 }, + { US"elifdef", 7, 2, 3, 0 }, + { US"elifndef", 8, 3, 2, 0 }, + { US"else", 4, 2, 2, 0 }, + { US"endif", 5, 0, 0, -1 } +}; + +static int cond_list_size = sizeof(cond_list)/sizeof(cond_item); + +/* Table of syslog facility names and their values */ + +static syslog_fac_item syslog_list[] = { + { US"mail", LOG_MAIL }, + { US"user", LOG_USER }, + { US"news", LOG_NEWS }, + { US"uucp", LOG_UUCP }, + { US"local0", LOG_LOCAL0 }, + { US"local1", LOG_LOCAL1 }, + { US"local2", LOG_LOCAL2 }, + { US"local3", LOG_LOCAL3 }, + { US"local4", LOG_LOCAL4 }, + { US"local5", LOG_LOCAL5 }, + { US"local6", LOG_LOCAL6 }, + { US"local7", LOG_LOCAL7 }, + { US"daemon", LOG_DAEMON } +}; + +static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item); + + + /************************************************* * Find the name of an option * @@ -554,6 +594,31 @@ return US""; * Deal with an assignment to a macro * *************************************************/ +/* We have a new definition; append to the list. + +Args: + name Name of the macro. Must be in storage persistent past the call + val Expansion result for the macro. Ditto persistence. +*/ + +macro_item * +macro_create(const uschar * name, const uschar * val, BOOL command_line) +{ +unsigned namelen = Ustrlen(name); +macro_item * m = store_get(sizeof(macro_item)); + +/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); */ +m->next = NULL; +m->command_line = command_line; +m->namelen = namelen; +m->name = name; +m->replacement = val; +mlast->next = m; +mlast = 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 @@ -566,14 +631,13 @@ Arguments: Returns: nothing */ -void +static void read_macro_assignment(uschar *s) { uschar name[64]; int namelen = 0; BOOL redef = FALSE; macro_item *m; -macro_item *mlast = NULL; while (isalnum(*s) || *s == '_') { @@ -599,13 +663,13 @@ 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. Note: it is documented that the other way round -works. */ +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. */ -for (m = macros; m != NULL; m = m->next) +for (m = macros; m; m = m->next) { - int len = Ustrlen(m->name); - if (Ustrcmp(m->name, name) == 0) { if (!m->command_line && !redef) @@ -614,7 +678,7 @@ for (m = macros; m != NULL; m = m->next) break; } - if (len < namelen && Ustrstr(name, m->name) != NULL) + if (m->namelen < namelen && Ustrstr(name, m->name) != NULL) log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as " "a macro because previously defined macro \"%s\" is a substring", name, m->name); @@ -622,45 +686,29 @@ for (m = macros; m != NULL; m = m->next) /* We cannot have this test, because it is documented that a substring macro is permitted (there is even an example). * - * if (len > namelen && Ustrstr(m->name, name) != NULL) + * 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); */ - - mlast = m; } /* Check for an overriding command-line definition. */ -if (m != NULL && m->command_line) return; +if (m && m->command_line) return; /* Redefinition must refer to an existing macro. */ if (redef) - { - if (m == NULL) + if (m) + m->replacement = string_copy(s); + else log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "can't redefine an undefined macro " "\"%s\"", name); - } - -/* We have a new definition. The macro_item structure includes a final vector -called "name" which is one byte long. Thus, adding "namelen" gives us enough -room to store the "name" string. */ +/* We have a new definition. */ else - { - m = store_get(sizeof(macro_item) + namelen); - if (macros == NULL) macros = m; else mlast->next = m; - Ustrncpy(m->name, name, namelen); - m->name[namelen] = 0; - m->next = NULL; - m->command_line = FALSE; - } - -/* Set the value of the new or redefined macro */ - -m->replacement = string_copy(s); + (void) macro_create(string_copy(name), string_copy(s), FALSE); } @@ -711,6 +759,7 @@ for (;;) (void)fclose(config_file); config_file = config_file_stack->file; config_filename = config_file_stack->filename; + config_directory = config_file_stack->directory; config_lineno = config_file_stack->lineno; config_file_stack = config_file_stack->next; if (config_lines) @@ -780,7 +829,7 @@ for (;;) replacing all occurrences of the macro. */ macro_found = FALSE; - for (m = macros; m != NULL; m = m->next) + for (m = macros; m; m = m->next) { uschar *p, *pp; uschar *t = s; @@ -788,12 +837,12 @@ for (;;) while ((p = Ustrstr(t, m->name)) != NULL) { int moveby; - int namelen = Ustrlen(m->name); int replen = Ustrlen(m->replacement); +/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, t); */ /* Expand the buffer if necessary */ - while (newlen - namelen + replen + 1 > big_buffer_size) + while (newlen - m->namelen + replen + 1 > big_buffer_size) { int newsize = big_buffer_size + BIG_BUFFER_SIZE; uschar *newbuffer = store_malloc(newsize); @@ -811,9 +860,8 @@ for (;;) copying in the replacement text. Don't rescan the replacement for this same macro. */ - pp = p + namelen; - moveby = replen - namelen; - if (moveby != 0) + pp = p + m->namelen; + if ((moveby = replen - m->namelen) != 0) { memmove(p + replen, pp, (big_buffer + newlen) - pp + 1); newlen += moveby; @@ -917,9 +965,19 @@ for (;;) } *t = 0; + /* We allow relative file names. For security reasons currently + relative names not allowed with .include_if_exists. For .include_if_exists + we need to check the permissions/ownership of the containing folder */ if (*ss != '/') - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, ".include specifies a non-" - "absolute path \"%s\"", ss); + if (include_if_exists) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, ".include specifies a non-" + "absolute path \"%s\"", ss); + else + { + int offset = 0; + int size = 0; + ss = string_append(NULL, &size, &offset, 3, config_directory, "/", ss); + ss[offset] = '\0'; /* string_append() does not zero terminate the string! */ + } if (include_if_exists != 0 && (Ustat(ss, &statbuf) != 0)) continue; @@ -930,6 +988,7 @@ for (;;) config_file_stack = save; save->file = config_file; save->filename = config_filename; + save->directory = config_directory; save->lineno = config_lineno; if (!(config_file = Ufopen(ss, "rb"))) @@ -937,6 +996,7 @@ for (;;) "configuration file %s", ss); config_filename = string_copy(ss); + config_directory = string_copyn(ss, CUstrrchr(ss, '/') - ss); config_lineno = 0; continue; } @@ -1630,9 +1690,13 @@ switch (type) const uschar * list = sptr; uschar * s; uschar * list_o = *str_target; + int size = 0, len = 0; + + if (list_o) + size = (len = Ustrlen(list_o)) + 1; while ((s = string_nextinlist(&list, &sep_i, NULL, 0))) - list_o = string_append_listele(list_o, sep_o, s); + list_o = string_append_listele(list_o, &size, &len, sep_o, s); if (list_o) *str_target = string_copy_malloc(list_o); } @@ -2101,6 +2165,11 @@ switch (type) if (value < 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "integer \"%s\" is too large (overflow)", s); + /* We get a coverity error here for using count, as it derived + from the tainted buffer pointed to by s, as parsed by sscanf(). + By the definition of sscanf we must be accessing between start + and end of s (assuming it is nul-terminated...) so ignore the error. */ + /* coverity[tainted_data] */ if (s[count] == '.') { int d = 100; @@ -2767,19 +2836,17 @@ else if (Ustrcmp(type, "macro") == 0) fprintf(stderr, "exim: permission denied\n"); exit(EXIT_FAILURE); } - for (m = macros; m != NULL; m = m->next) - { - if (name == NULL || Ustrcmp(name, m->name) == 0) + for (m = macros; m; m = m->next) + if (!name || Ustrcmp(name, m->name) == 0) { if (names_only) printf("%s\n", CS m->name); else printf("%s=%s\n", CS m->name, CS m->replacement); - if (name != NULL) + if (name) return; } - } - if (name != NULL) + if (name) printf("%s %s not found\n", type, name); return; } @@ -2982,12 +3049,9 @@ if (pid == 0) exim_setugid(exim_uid, exim_gid, FALSE, US"calling tls_validate_require_cipher"); - errmsg = tls_validate_require_cipher(); - if (errmsg) - { + if ((errmsg = tls_validate_require_cipher())) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "tls_require_ciphers invalid: %s", errmsg); - } fflush(NULL); _exit(0); } @@ -3009,196 +3073,6 @@ return status == 0; -/*************************************************/ -/* Create compile-time feature macros */ -void -readconf_features(void) -{ -/* Probably we could work out a static initialiser for wherever -macros are stored, but this will do for now. Some names are awkward -due to conflicts with other common macros. */ - -#ifdef SUPPORT_CRYPTEQ - read_macro_assignment(US"_HAVE_CRYPTEQ=y"); -#endif -#if HAVE_ICONV - read_macro_assignment(US"_HAVE_ICONV=y"); -#endif -#if HAVE_IPV6 - read_macro_assignment(US"_HAVE_IPV6=y"); -#endif -#ifdef HAVE_SETCLASSRESOURCES - read_macro_assignment(US"_HAVE_SETCLASSRESOURCES=y"); -#endif -#ifdef SUPPORT_PAM - read_macro_assignment(US"_HAVE_PAM=y"); -#endif -#ifdef EXIM_PERL - read_macro_assignment(US"_HAVE_PERL=y"); -#endif -#ifdef EXPAND_DLFUNC - read_macro_assignment(US"_HAVE_DLFUNC=y"); -#endif -#ifdef USE_TCP_WRAPPERS - read_macro_assignment(US"_HAVE_TCPWRAPPERS=y"); -#endif -#ifdef SUPPORT_TLS - read_macro_assignment(US"_HAVE_TLS=y"); -# ifdef USE_GNUTLS - read_macro_assignment(US"_HAVE_GNUTLS=y"); -# else - read_macro_assignment(US"_HAVE_OPENSSL=y"); -# endif -#endif -#ifdef SUPPORT_TRANSLATE_IP_ADDRESS - read_macro_assignment(US"_HAVE_TRANSLATE_IP_ADDRESS=y"); -#endif -#ifdef SUPPORT_MOVE_FROZEN_MESSAGES - read_macro_assignment(US"_HAVE_MOVE_FROZEN_MESSAGES=y"); -#endif -#ifdef WITH_CONTENT_SCAN - read_macro_assignment(US"_HAVE_CONTENT_SCANNING=y"); -#endif -#ifndef DISABLE_DKIM - read_macro_assignment(US"_HAVE_DKIM=y"); -#endif -#ifndef DISABLE_DNSSEC - read_macro_assignment(US"_HAVE_DNSSEC=y"); -#endif -#ifndef DISABLE_EVENT - read_macro_assignment(US"_HAVE_EVENT=y"); -#endif -#ifdef SUPPORT_I18N - read_macro_assignment(US"_HAVE_I18N=y"); -#endif -#ifndef DISABLE_OCSP - read_macro_assignment(US"_HAVE_OCSP=y"); -#endif -#ifndef DISABLE_PRDR - read_macro_assignment(US"_HAVE_PRDR=y"); -#endif -#ifdef SUPPORT_PROXY - read_macro_assignment(US"_HAVE_PROXY=y"); -#endif -#ifdef SUPPORT_SOCKS - read_macro_assignment(US"_HAVE_SOCKS=y"); -#endif -#ifdef EXPERIMENTAL_LMDB - read_macro_assignment(US"_HAVE_LMDB=y"); -#endif -#ifdef EXPERIMENTAL_SPF - read_macro_assignment(US"_HAVE_SPF=y"); -#endif -#ifdef EXPERIMENTAL_SRS - read_macro_assignment(US"_HAVE_SRS=y"); -#endif -#ifdef EXPERIMENTAL_BRIGHTMAIL - read_macro_assignment(US"_HAVE_BRIGHTMAIL=y"); -#endif -#ifdef EXPERIMENTAL_DANE - read_macro_assignment(US"_HAVE_DANE=y"); -#endif -#ifdef EXPERIMENTAL_DCC - read_macro_assignment(US"_HAVE_DCC=y"); -#endif -#ifdef EXPERIMENTAL_DMARC - read_macro_assignment(US"_HAVE_DMARC=y"); -#endif -#ifdef EXPERIMENTAL_DSN_INFO - read_macro_assignment(US"_HAVE_DSN_INFO=y"); -#endif - -#ifdef LOOKUP_LSEARCH - read_macro_assignment(US"_HAVE_LKUP_LSEARCH=y"); -#endif -#ifdef LOOKUP_CDB - read_macro_assignment(US"_HAVE_LKUP_CDB=y"); -#endif -#ifdef LOOKUP_DBM - read_macro_assignment(US"_HAVE_LKUP_DBM=y"); -#endif -#ifdef LOOKUP_DNSDB - read_macro_assignment(US"_HAVE_LKUP_DNSDB=y"); -#endif -#ifdef LOOKUP_DSEARCH - read_macro_assignment(US"_HAVE_LKUP_DSEARCH=y"); -#endif -#ifdef LOOKUP_IBASE - read_macro_assignment(US"_HAVE_LKUP_IBASE=y"); -#endif -#ifdef LOOKUP_LDAP - read_macro_assignment(US"_HAVE_LKUP_LDAP=y"); -#endif -#ifdef EXPERIMENTAL_LMDB - read_macro_assignment(US"_HAVE_LKUP_LMDB=y"); -#endif -#ifdef LOOKUP_MYSQL - read_macro_assignment(US"_HAVE_LKUP_MYSQL=y"); -#endif -#ifdef LOOKUP_NIS - read_macro_assignment(US"_HAVE_LKUP_NIS=y"); -#endif -#ifdef LOOKUP_NISPLUS - read_macro_assignment(US"_HAVE_LKUP_NISPLUS=y"); -#endif -#ifdef LOOKUP_ORACLE - read_macro_assignment(US"_HAVE_LKUP_ORACLE=y"); -#endif -#ifdef LOOKUP_PASSWD - read_macro_assignment(US"_HAVE_LKUP_PASSWD=y"); -#endif -#ifdef LOOKUP_PGSQL - read_macro_assignment(US"_HAVE_LKUP_PGSQL=y"); -#endif -#ifdef LOOKUP_REDIS - read_macro_assignment(US"_HAVE_LKUP_REDIS=y"); -#endif -#ifdef LOOKUP_SQLITE - read_macro_assignment(US"_HAVE_LKUP_SQLITE=y"); -#endif -#ifdef LOOKUP_TESTDB - read_macro_assignment(US"_HAVE_LKUP_TESTDB=y"); -#endif -#ifdef LOOKUP_WHOSON - read_macro_assignment(US"_HAVE_LKUP_WHOSON=y"); -#endif - -#ifdef TRANSPORT_APPENDFILE -# ifdef SUPPORT_MAILDIR - read_macro_assignment(US"_HAVE_TPT_APPEND_MAILDR=y"); -# endif -# ifdef SUPPORT_MAILSTORE - read_macro_assignment(US"_HAVE_TPT_APPEND_MAILSTORE=y"); -# endif -# ifdef SUPPORT_MBX - read_macro_assignment(US"_HAVE_TPT_APPEND_MBX=y"); -# endif -#endif -} - - -void -readconf_options_from_list(optionlist * opts, unsigned nopt, uschar * group) -{ -int i; -const uschar * s; - -/* Walk the array backwards to get substring-conflict names */ -for (i = nopt-1; i >= 0; i--) if (*(s = opts[i].name) && *s != '*') - read_macro_assignment(string_sprintf("_OPT_%T_%T=y", group, s)); -} - - -void -readconf_options(void) -{ -readconf_options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN"); -readconf_options_routers(); -readconf_options_transports(); -readconf_options_auths(); -} - - /************************************************* * Read main configuration options * *************************************************/ @@ -3237,8 +3111,7 @@ const uschar *list = config_main_filelist; /* Loop through the possible file names */ -while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) - != NULL) +while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) { /* Cut out all the fancy processing unless specifically wanted */ @@ -3294,28 +3167,50 @@ while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) if (config_file != NULL || errno != ENOENT) break; } -/* Now, once we found and opened our configuration file, we change the directory -to a safe place. Later we change to $spool_directory. */ - -if (Uchdir("/") < 0) - { - perror("exim: chdir `/': "); - exit(EXIT_FAILURE); - } - /* On success, save the name for verification; config_filename is used when logging configuration errors (it changes for .included files) whereas config_main_filename is the name shown by -bP. Failure to open a configuration file is a serious disaster. */ -if (config_file != NULL) +if (config_file) { - uschar *p; + uschar *last_slash = Ustrrchr(filename, '/'); config_filename = config_main_filename = string_copy(filename); - p = Ustrrchr(filename, '/'); - config_main_directory = p ? string_copyn(filename, p - filename) - : string_copy(US"."); + /* The config_main_directory we need for the $config_dir expansion. + config_main_filename we need for $config_file expansion. + And config_dir is the directory of the current configuration, used for + relative .includes. We do need to know it's name, as we change our working + directory later. */ + + if (filename[0] == '/') + config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename); + else + { + /* relative configuration file name: working dir + / + basename(filename) */ + + uschar buf[PATH_MAX]; + int offset = 0; + int size = 0; + + if (os_getcwd(buf, PATH_MAX) == NULL) + { + perror("exim: getcwd"); + exit(EXIT_FAILURE); + } + config_main_directory = string_cat(NULL, &size, &offset, buf); + + /* If the dir does not end with a "/", append one */ + if (config_main_directory[offset-1] != '/') + config_main_directory = string_catn(config_main_directory, &size, &offset, US"/", 1); + + /* If the config file contains a "/", extract the directory part */ + if (last_slash) + config_main_directory = string_catn(config_main_directory, &size, &offset, filename, last_slash - filename); + + config_main_directory[offset] = '\0'; + } + config_directory = config_main_directory; } else { @@ -3327,6 +3222,15 @@ else "configuration file %s", filename)); } +/* Now, once we found and opened our configuration file, we change the directory +to a safe place. Later we change to $spool_directory. */ + +if (Uchdir("/") < 0) + { + perror("exim: chdir `/': "); + exit(EXIT_FAILURE); + } + /* 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). */ @@ -3359,6 +3263,11 @@ a macro definition. */ while ((s = get_config_line()) != NULL) { + + if (config_lineno == 1 && Ustrstr(s, "\xef\xbb\xbf") == s) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, + "found unexpected BOM (Byte Order Mark)"); + if (isupper(s[0])) read_macro_assignment(s); else if (Ustrncmp(s, "domainlist", 10) == 0) @@ -3677,14 +3586,14 @@ if (tls_dh_max_bits < 1024) "tls_dh_max_bits is too small, must be at least 1024 for interop"); /* If openssl_options is set, validate it */ -if (openssl_options != NULL) +if (openssl_options) { # ifdef USE_GNUTLS log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "openssl_options is set but we're using GnuTLS"); # else long dummy; - if (!(tls_openssl_options_parse(openssl_options, &dummy))) + if (!tls_openssl_options_parse(openssl_options, &dummy)) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "openssl_options parse error: %s", openssl_options); # endif @@ -4240,21 +4149,6 @@ while ((p = get_config_line())) * Initialize authenticators * *************************************************/ -static void -readconf_options_auths(void) -{ -struct auth_info * ai; - -readconf_options_from_list(optionlist_auths, optionlist_auths_size, US"AU"); - -for (ai = auths_available; ai->driver_name[0]; ai++) - { - read_macro_assignment(string_sprintf("_DRVR_AUTH_%T=y", ai->driver_name)); - readconf_options_from_list(ai->options, (unsigned)*ai->options_count, ai->driver_name); - } -} - - /* Read the authenticators section of the configuration file. Arguments: none @@ -4586,6 +4480,7 @@ for (i = config_lines; i; i = i->next) } } +#endif /*!MACRO_PREDEF*/ /* vi: aw ai sw=2 */ /* End of readconf.c */