/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "hash.h"
#include "strescape.h"
#include "istream.h"
#include "module-dir.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "master-service-ssl-settings.h"
#include "all-settings.h"
#include "old-set-parser.h"
#include "config-request.h"
#include "config-parser-private.h"
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
#ifndef GLOB_BRACE
# define GLOB_BRACE 0
#endif
const char **error_r);
{
unsigned int i;
}
i_panic("setting parser: Invalid type_offset value");
return NULL;
}
const char *line, const char *section_name)
{
const char *p;
int ret;
/* section inside strlist */
return -1;
}
return 0;
}
return 0;
}
static bool
{
filter->remote_bits > 0;
}
static void
{
return;
}
static const char *
{
}
const char *line, const char *section_name)
{
struct config_module_parser *l;
int ret;
if (ret > 0) {
/* FIXME: remove once auth does support these. */
return -1;
}
if (section_name != NULL) {
return -1;
}
}
} else if (ret < 0) {
return -1;
}
}
if (!found) {
return -1;
}
return 0;
}
static const char *
{
const char *p;
if (*path == '/')
return path;
if (p == NULL)
return path;
}
static struct config_module_parser *
{
unsigned int i, count;
for (i = 0; i < count; i++) {
}
return dest;
}
static void
{
} else {
}
}
static struct config_section_stack *
{
return section;
}
static struct config_filter_parser *
const struct config_filter *filter)
{
return parser;
}
return NULL;
}
{
const char *p;
int ret;
return 0;
if (p != NULL) {
p++;
}
alarm(0);
if (ret != 0) {
return -1;
}
i_warning("gethostbyname(%s) took %d seconds",
}
if (p == NULL)
else {
return -1;
}
return 0;
}
static bool
{
const char *error;
else
if (parent->remote_bits > 0)
(parent->local_bits > 0 &&
parent->local_bits)))
else
if (parent->remote_bits > 0)
ctx->error = "protocol { local_name { .. } } not allowed (use local_name { protocol { .. } } instead)";
else
(parent->remote_bits > 0 &&
&parent->remote_net,
parent->remote_bits)))
else
} else {
return FALSE;
}
else
return TRUE;
}
static int
const struct config_module_parser *p,
const char **error_r)
{
const char *error;
bool ok;
/* skip checking settings we don't care about */
continue;
T_BEGIN {
if (!ok)
} T_END;
if (!ok) {
return -1;
}
}
return 0;
}
static const char *
const char *default_value)
{
const char *const *set_value;
return *set_value;
}
}
return default_value;
}
static int
struct config_filter_context *new_filter,
const char **error_r)
{
unsigned int i, count;
int ret = 0;
"Missing '}' (section started at %s:%u)",
return -1;
}
count--;
&tmp_parsers, &output,
error_r) < 0) {
ret = -1;
break;
}
i_warning("SSL is disabled because global ssl=no, "
"ignoring ssl=%s for subsection", ssl_set);
ssl_warned = TRUE;
}
}
return ret;
}
static int
const char **error_r)
{
int fd;
if (fd == -1) {
return -1;
}
if (ret < 0) {
}
i_close_fd(&fd);
return ret < 0 ? -1 : 0;
}
bool ignore_errors, const char **error_r)
{
int fd;
break;
}
return -1;
}
if (ignore_errors)
return 0;
path);
return -1;
}
return 0;
}
static int
bool ignore_errors)
{
const char *error;
#ifdef HAVE_GLOB
unsigned int i;
case 0:
break;
case GLOB_NOSPACE:
return -1;
case GLOB_ABORTED:
return -1;
case GLOB_NOMATCH:
if (ignore_errors)
return 0;
return -1;
default:
return -1;
}
/* iterate through the different files matching the globbing */
ignore_errors, &error) < 0) {
return -1;
}
}
return 0;
#else
return -1;
}
return 0;
#endif
}
static enum config_line_type
{
const char *key;
char *p;
/* @UNSAFE: line is modified */
/* skip whitespace */
line++;
/* ignore comments or empty lines */
return CONFIG_LINE_TYPE_SKIP;
/* strip away comments. pretty kludgy way really.. */
for (p = line; *p != '\0'; p++) {
if (*p == '\'' || *p == '"') {
char quote = *p;
for (p++; *p != quote && *p != '\0'; p++) {
if (*p == '\\' && p[1] != '\0')
p++;
}
if (*p == '\0')
break;
} else if (*p == '#') {
if (!IS_WHITE(p[-1])) {
i_warning("Configuration file %s line %u: "
"Ambiguous '#' character in line, treating it as comment. "
"Add a space before it to remove this warning.",
}
*p = '\0';
break;
}
}
/* remove whitespace from end of line */
while (len >= 1) {
break;
len--;
}
/* continues in next line */
len--;
while (len >= 1) {
break;
len--;
}
if(len >= 1) {
}
return CONFIG_LINE_TYPE_CONTINUE;
}
}
/* a) key = value
b) section_type [section_name] {
c) } */
line++;
*line++ = '\0';
}
return CONFIG_LINE_TYPE_INCLUDE;
return CONFIG_LINE_TYPE_INCLUDE_TRY;
if (*line == '=') {
/* a) */
*line++ = '\0';
if (*line == '<') {
return CONFIG_LINE_TYPE_KEYFILE;
}
if (*line == '$') {
return CONFIG_LINE_TYPE_KEYVARIABLE;
}
if (len > 0 &&
}
return CONFIG_LINE_TYPE_KEYVALUE;
}
return CONFIG_LINE_TYPE_SECTION_END;
/* b) + errors */
if (*line == '{')
*value_r = "";
else {
/* get section name */
if (*line != '"') {
line++;
if (*line != '\0') {
*line++ = '\0';
line++;
}
} else {
line++;
if (*line == '"') {
*line++ = '\0';
line++;
}
}
if (*line != '{') {
*value_r = "Expecting '{'";
return CONFIG_LINE_TYPE_ERROR;
}
}
*value_r = "Garbage after '{'";
return CONFIG_LINE_TYPE_ERROR;
}
return CONFIG_LINE_TYPE_SECTION_BEGIN;
}
{
const char *error;
int ret = 0;
if (hook_config_parser_end != NULL)
if (ret < 0)
;
else if (ctx->hide_errors)
ret = 0;
}
if (config_filter != NULL)
return ret;
}
static const void *
{
struct config_module_parser *l;
const void *value;
return value;
/* not changed by this parser. maybe parent has. */
}
}
return NULL;
}
static bool
{
struct config_module_parser *l;
return TRUE;
return TRUE;
}
return FALSE;
}
enum config_line_type type,
{
switch (type) {
break;
case CONFIG_LINE_TYPE_KEYFILE:
if (!ctx->expand_values) {
} else {
/* don't even try to open the file */
} else {
/* file reading failed */
return -1;
}
}
}
break;
/* expand_parent=TRUE for "key = $key stuff".
we'll always expand it so that doveconf -n can give
usable output */
if (p == NULL)
else
} else {
"Unknown variable: $",
return -1;
}
"Invalid variable: $",
return -1;
}
if (p != NULL)
str_append(str, p);
}
break;
default:
i_unreached();
}
return 0;
}
static void
{
/* changing a root setting. if we've already seen it inside
filters, log a warning. */
return;
i_warning("%s line %u: Global setting %s won't change the setting inside an earlier filter at %s "
"(if this is intentional, avoid this warning by moving the global setting before %s)",
return;
}
return;
}
enum config_line_type type,
{
const char *section_name;
switch (type) {
case CONFIG_LINE_TYPE_SKIP:
break;
i_unreached();
case CONFIG_LINE_TYPE_ERROR:
break;
case CONFIG_LINE_TYPE_KEYFILE:
break;
break;
/* new filter */
break;
}
/* new config section */
if (*value == '\0') {
/* no section name, use a counter */
} else {
}
break;
break;
else {
}
break;
case CONFIG_LINE_TYPE_INCLUDE:
break;
}
}
{
unsigned int i, count;
char *line;
bool handled;
path = "<defaults>";
fd = -1;
} else {
if (fd < 0) {
return 0;
}
}
for (i = 0; i < count; i++) {
}
i_stream_create_from_data("", 0);
} T_END;
if (type == CONFIG_LINE_TYPE_CONTINUE)
continue;
T_BEGIN {
if (!handled)
} T_END;
"Error in configuration file %s line %d: %s",
ret = -2;
break;
}
str_truncate(full_line, 0);
}
goto prevfile;
if (ret == 0)
}
void config_parse_load_modules(void)
{
struct module *m;
unsigned int i, count;
}
} else {
if (service_set != NULL)
}
}
if (array_count(&new_roots) > 0) {
/* modules added new settings. add the defaults and start
using the new list. */
} else {
}
if (array_count(&new_services) > 0) {
/* module added new services. update the defaults. */
for (i = 0; i < count; i++)
} else {
}
}
const struct setting_parser_info *info)
{
const struct setting_parser_info *p;
/* we're trying to find info or its parents from root's dependencies. */
if (p == root)
return TRUE;
}
return TRUE;
}
}
return FALSE;
}
const char *const *modules,
const struct setting_parser_info *root)
{
struct config_module_parser *l;
return TRUE;
if (root == &master_service_setting_parser_info) {
/* everyone wants master service settings */
return TRUE;
}
continue;
/* see if we can find a way to get from the original parser
to this parser */
return TRUE;
}
return FALSE;
}
void config_parser_deinit(void)
{
}