/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "array.h"
#include "env-util.h"
#include "istream.h"
#include "net.h"
#include "str.h"
#include "ipwd.h"
#include "mkdir-parents.h"
#include "safe-mkdir.h"
#include "restrict-process-size.h"
#include "settings-parser.h"
#include "master-settings.h"
#include <stddef.h>
#include <dirent.h>
#include <unistd.h>
const char **error_r);
extern const struct setting_parser_info service_setting_parser_info;
};
.path = "",
.mode = 0600,
.user = "",
.group = "",
};
.struct_size = sizeof(struct file_listener_settings),
};
};
.name = "",
.address = "",
.port = 0,
.reuse_port = FALSE,
};
.struct_size = sizeof(struct inet_listener_settings),
};
};
.name = "",
.protocol = "",
.type = "",
.executable = "",
.user = "",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "",
.process_min_avail = 0,
.process_limit = 0,
.client_limit = 0,
.service_count = 0,
.idle_kill = 0,
};
.struct_size = sizeof(struct service_settings),
};
};
.base_dir = PKG_RUNDIR,
.instance_name = PACKAGE,
.protocols = "imap pop3 lmtp",
.listen = "*, ::",
.ssl = "yes:no:required",
.default_internal_user = "dovecot",
.default_internal_group = "dovecot",
.default_login_user = "dovenull",
.default_process_limit = 100,
.default_client_limit = 1000,
.default_idle_kill = 60,
.version_ignore = FALSE,
.first_valid_uid = 500,
.last_valid_uid = 0,
.first_valid_gid = 1,
.last_valid_gid = 0,
#ifndef CONFIG_BINARY
#else
.services = { { &config_all_services_buf,
sizeof(struct service_settings *) } },
#endif
};
.module_name = "master",
.struct_size = sizeof(struct master_settings),
};
/* <settings checks> */
static void
const struct master_settings *set)
{
/* $variable expansion is typically done by doveconf, but these
variables can come from built-in settings, so we need to expand
them here */
} else {
}
}
static void
{
/* $variable expansion is typically done by doveconf, but these
variables can come from built-in settings, so we need to expand
them here */
}
static bool
const char **error_r)
{
if (!array_is_created(l))
return TRUE;
*error_r = "path must not be empty";
return FALSE;
}
base_dir_len) == 0 &&
i_warning("You should remove base_dir prefix from "
}
}
return TRUE;
}
{
const char *str;
if (!array_is_created(l))
return;
}
}
}
const char **error_r)
{
else {
return FALSE;
}
return TRUE;
}
{
const char *p;
return;
}
static bool
{
return TRUE;
}
return FALSE;
}
#ifdef CONFIG_BINARY
static const struct service_settings *
{
extern struct master_settings master_default_settings;
return *setp;
}
return NULL;
}
#endif
static unsigned int
{
if ((*servicep)->client_limit != 0)
return (*servicep)->client_limit;
else
return set->default_client_limit;
}
}
return set->default_client_limit;
}
static bool
{
const char *const *strings;
#ifdef CONFIG_BINARY
#else
#endif
*error_r = "listen can't be set empty";
return FALSE;
}
/* drop trailing '/' */
}
if (set->last_valid_uid != 0 &&
*error_r = "first_valid_uid can't be larger than last_valid_uid";
return FALSE;
}
if (set->last_valid_gid != 0 &&
*error_r = "first_valid_gid can't be larger than last_valid_gid";
return FALSE;
}
return FALSE;
}
return FALSE;
}
/* check that we have at least one service. the actual service
structure validity is checked later while creating them. */
*error_r = "No services defined";
return FALSE;
}
for (i = 0; i < count; i++) {
"Service #%d is missing name", i);
return FALSE;
}
return FALSE;
for (j = 0; j < i; j++) {
"Duplicate service name: %s",
return FALSE;
}
}
}
"Unknown protocol: %s",
set->protocols_split[i]);
return FALSE;
}
}
for (i = 0; i < count; i++) {
/* protocol not enabled, ignore its settings */
continue;
}
}
}
if (service->drop_priv_before_exec &&
"drop_priv_before_exec=yes can't be "
return FALSE;
}
if (process_limit == 0)
"process_min_avail is higher than process_limit",
return FALSE;
}
return FALSE;
}
#ifdef CONFIG_BINARY
if (default_service != NULL &&
return FALSE;
}
#else
}
#endif
although if service_count=1 it's only temporary.
imap-hibernate doesn't do any auth lookups. */
}
return FALSE;
}
return FALSE;
}
}
warned_auth = TRUE;
i_warning("service auth { client_limit=%u } is lower than "
"required under max. load (%u)",
}
warned_anvil = TRUE;
i_warning("service anvil { client_limit=%u } is lower than "
"required under max. load (%u)",
}
#ifndef CONFIG_BINARY
if (restrict_get_fd_limit(&fd_limit) == 0 &&
i_warning("fd limit (ulimit -n) is lower than required "
"under max. load (%u < %u), because of %s",
(unsigned int)fd_limit, max_client_limit,
}
#endif
/* check for duplicate listeners */
for (i = 1; i < count; i++) {
strings[i]);
return FALSE;
}
}
return TRUE;
}
/* </settings checks> */
static bool
{
const char *error;
if (service->login_dump_core)
}
}
return cores;
}
static bool
const char *dir)
{
struct file_listener_settings *u = *uls;
return TRUE;
}
}
}
return FALSE;
}
{
return;
}
continue;
continue;
str_truncate(str, 0);
continue;
}
continue;
/* try to avoid unlinking sockets if someone's already
listening in them. do this only at startup, because
when SIGHUPing a child process might catch the new
connection before it notices that it's supposed
to die. */
if (!startup_finished) {
i_fatal("Dovecot is already running? "
"Socket already exists: %s",
}
}
}
}
static void
{
/* we are not using external authentication, so make sure the
login directory exists with correct permissions and it's
empty. with external auth we wouldn't want to delete
existing sockets or break the permissions required by the
auth server. */
i_warning("Corrected permissions for login directory "
"%s", login_dir);
}
} else {
/* still make sure that login directory exists */
}
}
{
const char *empty_dir;
deleted. */
/* allow base_dir to be a symlink, so don't use lstat() */
i_warning("Fixing permissions of %s to be world-readable",
}
/* Make sure our permanent state directory exists */
i_warning("Corrected permissions for empty directory "
"%s", empty_dir);
}
}