X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Freadconf.c;h=8d5f38c58c24105e93ad2c14164ab0a8b0554ec4;hb=a65104203283ead15a6101f548107b95a450c7c9;hp=f831f866a3ecd11ff667581aab7b4fa0bafc2e6b;hpb=5903c6ff59527362e869fedb565c56935ce8dd68;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/readconf.c b/src/src/readconf.c index f831f866a..8d5f38c58 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2016 */ +/* Copyright (c) University of Cambridge 1995 - 2017 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for reading the configuration file, and for displaying @@ -615,7 +615,10 @@ m->namelen = Ustrlen(name); m->replen = Ustrlen(val); m->name = name; m->replacement = val; -mlast->next = m; +if (mlast) + mlast->next = m; +else + macros = m; mlast = m; return m; } @@ -630,11 +633,11 @@ non-command line, macros is permitted using '==' instead of '='. Arguments: s points to the start of the logical line -Returns: nothing +Returns: FALSE iff fatal error */ -static void -read_macro_assignment(uschar *s) +BOOL +macro_read_assignment(uschar *s) { uschar name[64]; int namelen = 0; @@ -644,15 +647,21 @@ macro_item *m; while (isalnum(*s) || *s == '_') { if (namelen >= sizeof(name) - 1) - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, + { + log_write(0, LOG_PANIC|LOG_CONFIG_IN, "macro name too long (maximum is " SIZE_T_FMT " characters)", sizeof(name) - 1); + return FALSE; + } name[namelen++] = *s++; } name[namelen] = 0; while (isspace(*s)) s++; if (*s++ != '=') - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "malformed macro definition"); + { + log_write(0, LOG_PANIC|LOG_CONFIG_IN, "malformed macro definition"); + return FALSE; + } if (*s == '=') { @@ -675,15 +684,21 @@ for (m = macros; m; m = m->next) if (Ustrcmp(m->name, name) == 0) { if (!m->command_line && !redef) - log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "macro \"%s\" is already " + { + log_write(0, LOG_CONFIG|LOG_PANIC, "macro \"%s\" is already " "defined (use \"==\" if you want to redefine it", name); + return FALSE; + } break; } if (m->namelen < namelen && Ustrstr(name, m->name) != NULL) - log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as " + { + 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; + } /* We cannot have this test, because it is documented that a substring macro is permitted (there is even an example). @@ -697,7 +712,7 @@ for (m = macros; m; m = m->next) /* Check for an overriding command-line definition. */ -if (m && m->command_line) return; +if (m && m->command_line) return TRUE; /* Redefinition must refer to an existing macro. */ @@ -708,18 +723,119 @@ if (redef) m->replacement = string_copy(s); } else - log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "can't redefine an undefined macro " + { + log_write(0, LOG_CONFIG|LOG_PANIC, "can't redefine an undefined macro " "\"%s\"", name); + return FALSE; + } /* We have a new definition. */ else (void) macro_create(string_copy(name), string_copy(s), FALSE); +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. + +Arguments: + len Offset in buffer of start of line + newlen Pointer to offset of end of line, updated on return + macro_found Pointer to return that a macro was expanded + +Return: pointer to first nonblank char in line +*/ + +uschar * +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. */ + +while (isspace(*ss)) ss++; + +/* Process the physical line for macros. If this is the start of the logical +line, skip over initial text at the start of the line if it starts with an +upper case character followed by a sequence of name characters and an equals +sign, because that is the definition of a new macro, and we don't do +replacement therein. */ + +s = ss; +if (len == 0 && isupper(*s)) + { + while (isalnum(*s) || *s == '_') s++; + while (isspace(*s)) s++; + if (*s != '=') s = ss; /* Not a macro definition */ + } + +/* Skip leading chars which cannot start a macro name, to avoid multiple +pointless rescans in Ustrstr calls. */ + +while (*s && !isupper(*s) && *s != '_') s++; + +/* For each defined macro, scan the line (from after XXX= if present), +replacing all occurrences of the macro. */ + +*macro_found = FALSE; +for (m = macros; m; m = m->next) + { + uschar * p, *pp; + uschar * t = s; + + while ((p = Ustrstr(t, m->name)) != NULL) + { + int moveby; + +/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, 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. */ + + 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 != '_') t++; + *macro_found = TRUE; + } + } + +/* An empty macro replacement at the start of a line could mean that ss no +longer points to the first non-blank character. */ + +while (isspace(*ss)) ss++; +return ss; +} + /************************************************* * Read configuration line * *************************************************/ @@ -749,7 +865,6 @@ int startoffset = 0; /* To first non-blank char in logical line */ int len = 0; /* Of logical line so far */ int newlen; uschar *s, *ss; -macro_item *m; BOOL macro_found; /* Loop for handling continuation lines, skipping comments, and dealing with @@ -810,82 +925,7 @@ for (;;) newlen += Ustrlen(big_buffer + newlen); } - /* Find the true start of the physical line - leading spaces are always - ignored. */ - - ss = big_buffer + len; - while (isspace(*ss)) ss++; - - /* Process the physical line for macros. If this is the start of the logical - line, skip over initial text at the start of the line if it starts with an - upper case character followed by a sequence of name characters and an equals - sign, because that is the definition of a new macro, and we don't do - replacement therein. */ - - s = ss; - if (len == 0 && isupper(*s)) - { - while (isalnum(*s) || *s == '_') s++; - while (isspace(*s)) s++; - if (*s != '=') s = ss; /* Not a macro definition */ - } - - /* Skip leading chars which cannot start a macro name, to avoid multiple - pointless rescans in Ustrstr calls. */ - - while (*s && !isupper(*s) && *s != '_') s++; - - /* For each defined macro, scan the line (from after XXX= if present), - replacing all occurrences of the macro. */ - - macro_found = FALSE; - for (m = macros; m; m = m->next) - { - uschar * p, *pp; - uschar * t = s; - - while ((p = Ustrstr(t, m->name)) != NULL) - { - int moveby; - -/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, 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. */ - - 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 != '_') t++; - macro_found = TRUE; - } - } - - /* An empty macro replacement at the start of a line could mean that ss no - longer points to the first non-blank character. */ - - while (isspace(*ss)) ss++; + ss = macros_expand(len, &newlen, ¯o_found); /* Check for comment lines - these are physical lines. */ @@ -983,10 +1023,8 @@ for (;;) "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! */ + gstring * g = string_append(NULL, 3, config_directory, "/", ss); + ss = string_from_gstring(g); } if (include_if_exists != 0 && (Ustat(ss, &statbuf) != 0)) continue; @@ -1699,16 +1737,19 @@ switch (type) int sep_i = -(int)sep_o; const uschar * list = sptr; uschar * s; - uschar * list_o = *str_target; - int size = 0, len = 0; + gstring * list_o = NULL; - if (list_o) - size = (len = Ustrlen(list_o)) + 1; + if (*str_target) + { + list_o = string_get(Ustrlen(*str_target) + Ustrlen(sptr)); + list_o = string_cat(list_o, *str_target); + } while ((s = string_nextinlist(&list, &sep_i, NULL, 0))) - list_o = string_append_listele(list_o, &size, &len, sep_o, s); + list_o = string_append_listele(list_o, sep_o, s); + if (list_o) - *str_target = string_copy_malloc(list_o); + *str_target = string_copy_malloc(string_from_gstring(list_o)); } else { @@ -3200,25 +3241,24 @@ if (config_file) /* relative configuration file name: working dir + / + basename(filename) */ uschar buf[PATH_MAX]; - int offset = 0; - int size = 0; + gstring * g; if (os_getcwd(buf, PATH_MAX) == NULL) { perror("exim: getcwd"); exit(EXIT_FAILURE); } - config_main_directory = string_cat(NULL, &size, &offset, buf); + g = string_cat(NULL, 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 (g->s[g->ptr-1] != '/') + g = string_catn(g, 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); + g = string_catn(g, filename, last_slash - filename); - config_main_directory[offset] = '\0'; + config_main_directory = string_from_gstring(g); } config_directory = config_main_directory; } @@ -3271,14 +3311,14 @@ if (trusted_config && Ustrcmp(filename, US"/dev/null")) letter. If we see something starting with an upper case letter, it is taken as a macro definition. */ -while ((s = get_config_line()) != NULL) +while ((s = get_config_line())) { - 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); + if (isupper(s[0])) + { if (!macro_read_assignment(s)) exim_exit(EXIT_FAILURE, US""); } else if (Ustrncmp(s, "domainlist", 10) == 0) read_named_list(&domainlist_anchor, &domainlist_count, @@ -3441,7 +3481,7 @@ if (*log_file_path != 0) openlog(). Default is LOG_MAIL set in globals.c. Allow the user to omit the leading "log_". */ -if (syslog_facility_str != NULL) +if (syslog_facility_str) { int i; uschar *s = syslog_facility_str; @@ -3451,27 +3491,22 @@ if (syslog_facility_str != NULL) s += 4; for (i = 0; i < syslog_list_size; i++) - { if (strcmpic(s, syslog_list[i].name) == 0) { syslog_facility = syslog_list[i].value; break; } - } if (i >= syslog_list_size) - { log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "failed to interpret syslog_facility \"%s\"", syslog_facility_str); - } } /* Expand pid_file_path */ if (*pid_file_path != 0) { - s = expand_string(pid_file_path); - if (s == NULL) + if (!(s = expand_string(pid_file_path))) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path " "\"%s\": %s", pid_file_path, expand_string_message); pid_file_path = s; @@ -3479,7 +3514,7 @@ if (*pid_file_path != 0) /* Set default value of process_log_path */ -if (process_log_path == NULL || *process_log_path =='\0') +if (!process_log_path || *process_log_path =='\0') process_log_path = string_sprintf("%s/exim-process.info", spool_directory); /* Compile the regex for matching a UUCP-style "From_" line in an incoming @@ -3489,23 +3524,19 @@ regex_From = regex_must_compile(uucp_from_pattern, FALSE, TRUE); /* Unpick the SMTP rate limiting options, if set */ -if (smtp_ratelimit_mail != NULL) - { +if (smtp_ratelimit_mail) unpick_ratelimit(smtp_ratelimit_mail, &smtp_rlm_threshold, &smtp_rlm_base, &smtp_rlm_factor, &smtp_rlm_limit); - } -if (smtp_ratelimit_rcpt != NULL) - { +if (smtp_ratelimit_rcpt) unpick_ratelimit(smtp_ratelimit_rcpt, &smtp_rlr_threshold, &smtp_rlr_base, &smtp_rlr_factor, &smtp_rlr_limit); - } /* The qualify domains default to the primary host name */ -if (qualify_domain_sender == NULL) +if (!qualify_domain_sender) qualify_domain_sender = primary_hostname; -if (qualify_domain_recipient == NULL) +if (!qualify_domain_recipient) qualify_domain_recipient = qualify_domain_sender; /* Setting system_filter_user in the configuration sets the gid as well if a @@ -3514,7 +3545,7 @@ name is given, but a numerical value does not. */ if (system_filter_uid_set && !system_filter_gid_set) { struct passwd *pw = getpwuid(system_filter_uid); - if (pw == NULL) + if (!pw) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to look up uid %ld", (long int)system_filter_uid); system_filter_gid = pw->pw_gid; @@ -3524,14 +3555,14 @@ if (system_filter_uid_set && !system_filter_gid_set) /* If the errors_reply_to field is set, check that it is syntactically valid and ensure it contains a domain. */ -if (errors_reply_to != NULL) +if (errors_reply_to) { uschar *errmess; int start, end, domain; uschar *recipient = parse_extract_address(errors_reply_to, &errmess, &start, &end, &domain, FALSE); - if (recipient == NULL) + if (!recipient) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "error in errors_reply_to (%s): %s", errors_reply_to, errmess); @@ -3553,12 +3584,13 @@ if (smtp_accept_max == 0 && so that it can be computed from the host name, for example. We do this last so as to ensure that everything else is set up before the expansion. */ -if (host_number_string != NULL) +if (host_number_string) { long int n; uschar *end; uschar *s = expand_string(host_number_string); - if (s == NULL) + + if (!s) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand localhost_number \"%s\": %s", host_number_string, expand_string_message); @@ -3577,11 +3609,10 @@ if (host_number_string != NULL) #ifdef SUPPORT_TLS /* If tls_verify_hosts is set, tls_verify_certificates must also be set */ -if ((tls_verify_hosts != NULL || tls_try_verify_hosts != NULL) && - tls_verify_certificates == NULL) +if ((tls_verify_hosts || tls_try_verify_hosts) && !tls_verify_certificates) log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "tls_%sverify_hosts is set, but tls_verify_certificates is not set", - (tls_verify_hosts != NULL)? "" : "try_"); + tls_verify_hosts ? "" : "try_"); /* This also checks that the library linkage is working and we can call routines in it, so call even if tls_require_ciphers is unset */ @@ -3734,7 +3765,7 @@ while ((buffer = get_config_line()) != NULL) (d->info->init)(d); d = NULL; } - read_macro_assignment(buffer); + if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE, US""); continue; } @@ -4235,7 +4266,7 @@ between ACLs. */ acl_line = get_config_line(); -while(acl_line != NULL) +while(acl_line) { uschar name[64]; tree_node *node; @@ -4244,7 +4275,7 @@ while(acl_line != NULL) p = readconf_readname(name, sizeof(name), acl_line); if (isupper(*name) && *p == '=') { - read_macro_assignment(acl_line); + if (!macro_read_assignment(acl_line)) exim_exit(EXIT_FAILURE, US""); acl_line = get_config_line(); continue; } @@ -4288,7 +4319,7 @@ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "local_scan() options not supported: " #else uschar *p; -while ((p = get_config_line()) != NULL) +while ((p = get_config_line())) { (void) readconf_handle_option(p, local_scan_options, local_scan_options_count, NULL, US"local_scan option \"%s\" unknown"); @@ -4378,14 +4409,14 @@ while(next_section[0] != 0) void readconf_save_config(const uschar *s) { - save_config_line(string_sprintf("# Exim Configuration (%s)", - running_in_test_harness ? US"X" : s)); +save_config_line(string_sprintf("# Exim Configuration (%s)", + running_in_test_harness ? US"X" : s)); } static void save_config_position(const uschar *file, int line) { - save_config_line(string_sprintf("# %d \"%s\"", line, file)); +save_config_line(string_sprintf("# %d \"%s\"", line, file)); } /* Append a pre-parsed logical line to the config lines store,