X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c988f1f4faa9f679f79beddf3c14676c5dcb8e28..45b915963e2e3721fc65c7c3f50f2f65f5c54d1b:/src/src/readconf.c diff --git a/src/src/readconf.c b/src/src/readconf.c index 568c7050a..75d444ef1 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/readconf.c,v 1.4 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/readconf.c,v 1.23 2006/06/28 16:00:24 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2006 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for reading the configuration file, and for displaying @@ -135,6 +135,10 @@ static optionlist optionlist_config[] = { { "*set_system_filter_user", opt_bool|opt_hidden, &system_filter_uid_set }, { "accept_8bitmime", opt_bool, &accept_8bitmime }, { "acl_not_smtp", opt_stringptr, &acl_not_smtp }, +#ifdef WITH_CONTENT_SCAN + { "acl_not_smtp_mime", opt_stringptr, &acl_not_smtp_mime }, +#endif + { "acl_not_smtp_start", opt_stringptr, &acl_not_smtp_start }, { "acl_smtp_auth", opt_stringptr, &acl_smtp_auth }, { "acl_smtp_connect", opt_stringptr, &acl_smtp_connect }, { "acl_smtp_data", opt_stringptr, &acl_smtp_data }, @@ -179,17 +183,23 @@ static optionlist optionlist_config[] = { { "callout_random_local_part",opt_stringptr, &callout_random_local_part }, { "check_log_inodes", opt_int, &check_log_inodes }, { "check_log_space", opt_Kint, &check_log_space }, + { "check_rfc2047_length", opt_bool, &check_rfc2047_length }, { "check_spool_inodes", opt_int, &check_spool_inodes }, { "check_spool_space", opt_Kint, &check_spool_space }, { "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 }, + { "daemon_startup_sleep", opt_time, &daemon_startup_sleep }, { "delay_warning", opt_timelist, &delay_warning }, { "delay_warning_condition", opt_stringptr, &delay_warning_condition }, { "deliver_drop_privilege", opt_bool, &deliver_drop_privilege }, { "deliver_queue_load_max", opt_fixed, &deliver_queue_load_max }, { "delivery_date_remove", opt_bool, &delivery_date_remove }, + { "disable_ipv6", opt_bool, &disable_ipv6 }, { "dns_again_means_nonexist", opt_stringptr, &dns_again_means_nonexist }, { "dns_check_names_pattern", opt_stringptr, &check_dns_names_pattern }, + { "dns_csa_search_limit", opt_int, &dns_csa_search_limit }, + { "dns_csa_use_reverse", opt_bool, &dns_csa_use_reverse }, { "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup }, { "dns_retrans", opt_time, &dns_retrans }, { "dns_retry", opt_int, &dns_retry }, @@ -332,8 +342,17 @@ static optionlist optionlist_config[] = { #endif { "split_spool_directory", opt_bool, &split_spool_directory }, { "spool_directory", opt_stringptr, &spool_directory }, +#ifdef LOOKUP_SQLITE + { "sqlite_lock_timeout", opt_int, &sqlite_lock_timeout }, +#endif #ifdef EXPERIMENTAL_SRS { "srs_config", opt_stringptr, &srs_config }, + { "srs_hashlength", opt_int, &srs_hashlength }, + { "srs_hashmin", opt_int, &srs_hashmin }, + { "srs_maxage", opt_int, &srs_maxage }, + { "srs_secrets", opt_stringptr, &srs_secrets }, + { "srs_usehash", opt_bool, &srs_usehash }, + { "srs_usetimestamp", opt_bool, &srs_usetimestamp }, #endif { "strip_excess_angle_brackets", opt_bool, &strip_excess_angle_brackets }, { "strip_trailing_dot", opt_bool, &strip_trailing_dot }, @@ -432,6 +451,122 @@ return US""; +/************************************************* +* Deal with an assignment to a macro * +*************************************************/ + +/* 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 +replacement text are extracted and stored. Redefinition of existing, +non-command line, macros is permitted using '==' instead of '='. + +Arguments: + s points to the start of the logical line + +Returns: nothing +*/ + +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 == '_') + { + if (namelen >= sizeof(name) - 1) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, + "macro name too long (maximum is %d characters)", sizeof(name) - 1); + name[namelen++] = *s++; + } +name[namelen] = 0; + +while (isspace(*s)) s++; +if (*s++ != '=') + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "malformed macro definition"); + +if (*s == '=') + { + redef = TRUE; + s++; + } +while (isspace(*s)) s++; + +/* If an existing macro of the same name was defined on the command line, we +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. */ + +for (m = macros; m != NULL; m = m->next) + { + int len = Ustrlen(m->name); + + if (Ustrcmp(m->name, name) == 0) + { + if (!m->command_line && !redef) + log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "macro \"%s\" is already " + "defined (use \"==\" if you want to redefine it", name); + break; + } + + if (len < 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); + + /* 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) + * 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; + +/* Redefinition must refer to an existing macro. */ + +if (redef) + { + if (m == NULL) + 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. */ + +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); +} + + + + /************************************************* * Read configuration line * @@ -474,7 +609,7 @@ for (;;) { if (config_file_stack != NULL) /* EOF inside .include */ { - fclose(config_file); + (void)fclose(config_file); config_file = config_file_stack->file; config_filename = config_file_stack->filename; config_lineno = config_file_stack->lineno; @@ -678,6 +813,10 @@ for (;;) } *t = 0; + if (*ss != '/') + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, ".include specifies a non-" + "absolute path \"%s\"", ss); + if (include_if_exists != 0 && (Ustat(ss, &statbuf) != 0)) continue; save = store_get(sizeof(config_file_item)); @@ -1493,10 +1632,16 @@ switch (type) int count = 1; uid_t *list; int ptr = 0; - uschar *p = sptr; + uschar *p; + uschar *op = expand_string (sptr); + if (op == NULL) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "failed to expand %s: %s", + name, expand_string_message); + + p = op; if (*p != 0) count++; - while (*p != 0) if (*p++ == ':') count++; + while (*p != 0) if (*p++ == ':' && *p != 0) count++; list = store_malloc(count*sizeof(uid_t)); list[ptr++] = (uid_t)(count - 1); @@ -1505,7 +1650,7 @@ switch (type) else *((uid_t **)((uschar *)data_block + (long int)(ol->value))) = list; - p = sptr; + p = op; while (count-- > 1) { int sep = 0; @@ -1528,10 +1673,16 @@ switch (type) int count = 1; gid_t *list; int ptr = 0; - uschar *p = sptr; + uschar *p; + uschar *op = expand_string (sptr); + if (op == NULL) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "failed to expand %s: %s", + name, expand_string_message); + + p = op; if (*p != 0) count++; - while (*p != 0) if (*p++ == ':') count++; + while (*p != 0) if (*p++ == ':' && *p != 0) count++; list = store_malloc(count*sizeof(gid_t)); list[ptr++] = (gid_t)(count - 1); @@ -1540,7 +1691,7 @@ switch (type) else *((gid_t **)((uschar *)data_block + (long int)(ol->value))) = list; - p = sptr; + p = op; while (count-- > 1) { int sep = 0; @@ -1865,6 +2016,12 @@ readconf_printtime(int t) int s, m, h, d, w; uschar *p = time_buffer; +if (t < 0) + { + *p++ = '-'; + t = -t; + } + s = t % 60; t /= 60; m = t % 60; @@ -2613,7 +2770,7 @@ if (!config_changed) (statbuf.st_gid != exim_gid /* group not exim & */ #ifdef CONFIGURE_GROUP && statbuf.st_gid != config_gid /* group not the special one */ - #endif + #endif && (statbuf.st_mode & 020) != 0) || /* group writeable */ /* or */ ((statbuf.st_mode & 2) != 0)) /* world writeable */ @@ -2628,65 +2785,7 @@ a macro definition. */ while ((s = get_config_line()) != NULL) { - if (isupper(s[0])) - { - macro_item *m; - macro_item *mlast = NULL; - uschar name[64]; - int namelen = 0; - - while (isalnum(*s) || *s == '_') - { - if (namelen >= sizeof(name) - 1) - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, - "macro name too long (maximum is %d characters)", sizeof(name) - 1); - name[namelen++] = *s++; - } - name[namelen] = 0; - while (isspace(*s)) s++; - if (*s++ != '=') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, - "malformed macro definition"); - while (isspace(*s)) s++; - - /* If an existing macro of the same name was defined on the command line, - we just skip this definition. Otherwise it's an error to attempt to - redefine a macro. It is also an error to define a macro whose name begins - with the name of a previously-defined macro. */ - - for (m = macros; m != NULL; m = m->next) - { - int len = Ustrlen(m->name); - - if (Ustrcmp(m->name, name) == 0) - { - if (m->command_line) break; - log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "macro \"%s\" is already " - "defined", name); - } - - if (len < 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); - - mlast = m; - } - if (m != NULL) continue; /* Found an overriding command-line definition */ - - m = store_get(sizeof(macro_item) + namelen); - m->next = NULL; - m->command_line = FALSE; - if (mlast == NULL) macros = m; else mlast->next = m; - - /* This use of strcpy() is OK because we have obtained a block of store - whose size is based on the length of "name". The definition of 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. */ - - Ustrcpy(m->name, name); - m->replacement = string_copy(s); - } + if (isupper(s[0])) read_macro_assignment(s); else if (Ustrncmp(s, "domainlist", 10) == 0) read_named_list(&domainlist_anchor, &domainlist_count, @@ -2721,10 +2820,19 @@ wanted. */ if (timezone_string != NULL && *timezone_string == 0) timezone_string = NULL; +/* The max retry interval must not be greater than 24 hours. */ + +if (retry_interval_max > 24*60*60) retry_interval_max = 24*60*60; + /* remote_max_parallel must be > 0 */ if (remote_max_parallel <= 0) remote_max_parallel = 1; +/* Save the configured setting of freeze_tell, so we can re-instate it at the +start of a new SMTP message. */ + +freeze_tell_config = freeze_tell; + /* The primary host name may be required for expansion of spool_directory and log_file_path, so make sure it is set asap. It is obtained from uname(), but if that yields an unqualified value, make a FQDN by using gethostbyname to @@ -2745,9 +2853,9 @@ if (primary_hostname == NULL) struct hostent *hostdata; #if HAVE_IPV6 - if (dns_ipv4_lookup == NULL || + if (!disable_ipv6 && (dns_ipv4_lookup == NULL || match_isinlist(hostname, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN, - TRUE, NULL) != OK) + TRUE, NULL) != OK)) af = AF_INET6; #else af = AF_INET; @@ -3068,16 +3176,33 @@ driver_instance **p = anchor; driver_instance *d = NULL; uschar *buffer; -/* Now process the configuration lines */ - while ((buffer = get_config_line()) != NULL) { uschar name[64]; + uschar *s; - /* Read the first name on the line and test for the start of a new driver. - If this isn't the start of a new driver, the line will be re-read. */ + /* Read the first name on the line and test for the start of a new driver. A + macro definition indicates the end of the previous driver. If this isn't the + start of a new driver, the line will be re-read. */ - uschar *s = readconf_readname(name, sizeof(name), buffer); + s = readconf_readname(name, sizeof(name), buffer); + + /* Handle macro definition, first finishing off the initialization of the + previous driver, if any. */ + + if (isupper(*name) && *s == '=') + { + if (d != NULL) + { + if (d->driver_name == NULL) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG, + "no driver defined for %s \"%s\"", class, d->name); + (d->info->init)(d); + d = NULL; + } + read_macro_assignment(buffer); + continue; + } /* If the line starts with a name terminated by a colon, we are at the start of the definition of a new driver. The rest of the line must be @@ -3125,7 +3250,8 @@ while ((buffer = get_config_line()) != NULL) continue; } - /* Give an error if we have not set up a current driver yet. */ + /* Not the start of a new driver. Give an error if we have not set up a + current driver yet. */ if (d == NULL) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%s name missing", class); @@ -3296,7 +3422,9 @@ else if (len == 7 && strncmpic(pp, US"timeout", len) == 0) } } -else if (strncmpic(pp, US"rcpt_4", 6) == 0) +else if (strncmpic(pp, US"mail_4", 6) == 0 || + strncmpic(pp, US"rcpt_4", 6) == 0 || + strncmpic(pp, US"data_4", 6) == 0) { BOOL bad = FALSE; int x = 255; /* means "any 4xx code" */ @@ -3313,18 +3441,24 @@ else if (strncmpic(pp, US"rcpt_4", 6) == 0) else if (a != 'x' || b != 'x') bad = TRUE; } - if (bad) return US"rcpt_4 must be followed by xx, dx, or dd, where " - "x is literal and d is any digit"; + if (bad) + return string_sprintf("%.4s_4 must be followed by xx, dx, or dd, where " + "x is literal and d is any digit", pp); - *basic_errno = ERRNO_RCPT4XX; + *basic_errno = (*pp == 'm')? ERRNO_MAIL4XX : + (*pp == 'r')? ERRNO_RCPT4XX : ERRNO_DATA4XX; *more_errno = x << 8; } else if (len == 4 && strncmpic(pp, US"auth", len) == 0 && strncmpic(q+1, US"failed", p-q-1) == 0) - { *basic_errno = ERRNO_AUTHFAIL; - } + +else if (strcmpic(pp, US"lost_connection") == 0) + *basic_errno = ERRNO_SMTPCLOSED; + +else if (strcmpic(pp, US"tls_required") == 0) + *basic_errno = ERRNO_TLSREQUIRED; else if (len != 1 || Ustrncmp(pp, "*", 1) != 0) return string_sprintf("unknown or malformed retry error \"%.*s\"", p-pp, pp); @@ -3462,6 +3596,7 @@ while ((p = get_config_line()) != NULL) break; case 'G': /* Geometrically increasing intervals */ + case 'H': /* Ditto, but with randomness */ rule->p1 = retry_arg(&p, 0); rule->p2 = retry_arg(&p, 1); break; @@ -3472,7 +3607,7 @@ while ((p = get_config_line()) != NULL) } if (rule->timeout <= 0 || rule->p1 <= 0 || - (rule->rule == 'G' && rule->p2 < 1000)) + (rule->rule != 'F' && rule->p2 < 1000)) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "bad parameters for retry rule"); @@ -3579,7 +3714,8 @@ if (skip) return; } -/* Read each ACL and add it into the tree */ +/* Read each ACL and add it into the tree. Macro (re)definitions are allowed +between ACLs. */ acl_line = get_config_line(); @@ -3590,8 +3726,15 @@ while(acl_line != NULL) uschar *error; p = readconf_readname(name, sizeof(name), acl_line); - if (*p != ':') - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing ACL name"); + if (isupper(*name) && *p == '=') + { + read_macro_assignment(acl_line); + acl_line = get_config_line(); + continue; + } + + if (*p != ':' || name[0] == 0) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name"); node = store_get(sizeof(tree_node) + Ustrlen(name)); Ustrcpy(node->name, name); @@ -3714,7 +3857,7 @@ while(next_section[0] != 0) } } -fclose(config_file); +(void)fclose(config_file); } /* End of readconf.c */