/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file */ #include "lib.h" #include "sieve-common.h" #include "sieve-limits.h" #include "sieve-error.h" #include "sieve-address.h" #include "sieve-address-source.h" #include "sieve-settings.h" #include /* * Access to settings */ bool sieve_setting_get_uint_value(struct sieve_instance *svinst, const char *setting, unsigned long long int *value_r) { const char *str_value; str_value = sieve_setting_get(svinst, setting); if (str_value == NULL || *str_value == '\0') return FALSE; if (str_to_ullong(str_value, value_r) < 0) { e_warning(svinst->event, "invalid unsigned integer value for setting '%s': " "'%s'", setting, str_value); return FALSE; } return TRUE; } bool sieve_setting_get_int_value(struct sieve_instance *svinst, const char *setting, long long int *value_r) { const char *str_value; str_value = sieve_setting_get(svinst, setting); if (str_value == NULL || *str_value == '\0') return FALSE; if (str_to_llong(str_value, value_r) < 0) { e_warning(svinst->event, "invalid integer value for setting '%s': '%s'", setting, str_value); return FALSE; } return TRUE; } bool sieve_setting_get_size_value(struct sieve_instance *svinst, const char *setting, size_t *value_r) { const char *str_value; uintmax_t value, multiply = 1; const char *endp; str_value = sieve_setting_get(svinst, setting); if (str_value == NULL || *str_value == '\0') return FALSE; if (str_parse_uintmax(str_value, &value, &endp) < 0) { e_warning(svinst->event, "invalid size value for setting '%s': '%s'", setting, str_value); return FALSE; } switch (i_toupper(*endp)) { case '\0': /* default */ case 'B': /* byte (useless) */ multiply = 1; break; case 'K': /* kilobyte */ multiply = 1024; break; case 'M': /* megabyte */ multiply = 1024*1024; break; case 'G': /* gigabyte */ multiply = 1024*1024*1024; break; case 'T': /* terabyte */ multiply = 1024ULL*1024*1024*1024; break; default: e_warning(svinst->event, "invalid size value for setting '%s': '%s'", setting, str_value); return FALSE; } if (value > SSIZE_T_MAX / multiply) { e_warning(svinst->event, "overflowing size value for setting '%s': '%s'", setting, str_value); return FALSE; } *value_r = (size_t)(value * multiply); return TRUE; } bool sieve_setting_get_bool_value(struct sieve_instance *svinst, const char *setting, bool *value_r) { const char *str_value; str_value = sieve_setting_get(svinst, setting); if (str_value == NULL) return FALSE; str_value = t_str_trim(str_value, "\t "); if (*str_value == '\0') return FALSE; if (strcasecmp(str_value, "yes") == 0) { *value_r = TRUE; return TRUE; } if (strcasecmp(str_value, "no") == 0) { *value_r = FALSE; return TRUE; } e_warning(svinst->event, "invalid boolean value for setting '%s': '%s'", setting, str_value); return FALSE; } bool sieve_setting_get_duration_value(struct sieve_instance *svinst, const char *setting, sieve_number_t *value_r) { const char *str_value; uintmax_t value, multiply = 1; const char *endp; str_value = sieve_setting_get(svinst, setting); if (str_value == NULL) return FALSE; str_value = t_str_trim(str_value, "\t "); if (*str_value == '\0') return FALSE; if (str_parse_uintmax(str_value, &value, &endp) < 0) { e_warning(svinst->event, "invalid duration value for setting '%s': '%s'", setting, str_value); return FALSE; } switch (i_tolower(*endp)) { case '\0': /* default */ case 's': /* seconds */ multiply = 1; break; case 'm': /* minutes */ multiply = 60; break; case 'h': /* hours */ multiply = 60*60; break; case 'd': /* days */ multiply = 24*60*60; break; default: e_warning(svinst->event, "invalid duration value for setting '%s': '%s'", setting, str_value); return FALSE; } if (value > SIEVE_MAX_NUMBER / multiply) { e_warning(svinst->event, "overflowing duration value for setting '%s': '%s'", setting, str_value); return FALSE; } *value_r = (unsigned int)(value * multiply); return TRUE; } /* * Main Sieve engine settings */ void sieve_settings_load(struct sieve_instance *svinst) { const char *str_setting, *error; unsigned long long int uint_setting; size_t size_setting; sieve_number_t period; svinst->max_script_size = SIEVE_DEFAULT_MAX_SCRIPT_SIZE; if (sieve_setting_get_size_value(svinst, "sieve_max_script_size", &size_setting)) svinst->max_script_size = size_setting; svinst->max_actions = SIEVE_DEFAULT_MAX_ACTIONS; if (sieve_setting_get_uint_value(svinst, "sieve_max_actions", &uint_setting)) svinst->max_actions = (unsigned int)uint_setting; svinst->max_redirects = SIEVE_DEFAULT_MAX_REDIRECTS; if (sieve_setting_get_uint_value(svinst, "sieve_max_redirects", &uint_setting)) svinst->max_redirects = (unsigned int)uint_setting; svinst->max_cpu_time_secs = (svinst->env_location == SIEVE_ENV_LOCATION_MS ? 0 : SIEVE_DEFAULT_MAX_CPU_TIME_SECS); if (sieve_setting_get_duration_value(svinst, "sieve_max_cpu_time", &period)) { if (period > (UINT_MAX / 1000)) svinst->max_cpu_time_secs = (UINT_MAX / 1000); else svinst->max_cpu_time_secs = (unsigned int)period; } svinst->resource_usage_timeout_secs = SIEVE_DEFAULT_RESOURCE_USAGE_TIMEOUT_SECS; if (sieve_setting_get_duration_value( svinst, "sieve_resource_usage_timeout", &period)) { if (period > UINT_MAX) svinst->resource_usage_timeout_secs = UINT_MAX; else { svinst->resource_usage_timeout_secs = (unsigned int)period; } } (void)sieve_address_source_parse_from_setting( svinst, svinst->pool, "sieve_redirect_envelope_from", &svinst->redirect_from); svinst->redirect_duplicate_period = DEFAULT_REDIRECT_DUPLICATE_PERIOD; if (sieve_setting_get_duration_value( svinst, "sieve_redirect_duplicate_period", &period)) { if (period > UINT_MAX) svinst->redirect_duplicate_period = UINT_MAX; else { svinst->redirect_duplicate_period = (unsigned int)period; } } str_setting = sieve_setting_get(svinst, "sieve_user_email"); if (str_setting != NULL && *str_setting != '\0') { struct smtp_address *address; if (smtp_address_parse_path( svinst->pool, str_setting, SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL, &address, &error) < 0) { e_warning(svinst->event, "Invalid address value for setting " "`sieve_user_email': %s", error); } else { svinst->user_email = address; } } }