master-service-settings.c revision 194755bdfb97c07ca8b9df071099f68947b971e3
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "lib.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "array.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "abspath.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include "istream.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "write-full.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "str.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "settings-parser.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include "master-service-private.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include "master-service-settings.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <stddef.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <stdlib.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <unistd.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <time.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <sys/stat.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define DOVECOT_CONFIG_SOCKET_PATH PKG_RUNDIR"/config"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define CONFIG_READ_TIMEOUT_SECS 10
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define CONFIG_HANDSHAKE "VERSION\tconfig\t2\t0\n"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#undef DEF
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define DEF(type, name) \
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen { type, #name, offsetof(struct master_service_settings, name), NULL }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic const struct setting_define master_service_setting_defines[] = {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen DEF(SET_STR, log_path),
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen DEF(SET_STR, info_log_path),
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen DEF(SET_STR, debug_log_path),
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen DEF(SET_STR, log_timestamp),
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen DEF(SET_STR, syslog_facility),
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen DEF(SET_SIZE, config_cache_size),
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen DEF(SET_BOOL, version_ignore),
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen DEF(SET_BOOL, shutdown_clients),
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen SETTING_DEFINE_LIST_END
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen};
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic const struct master_service_settings master_service_default_settings = {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen .log_path = "",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen .info_log_path = "",
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .debug_log_path = "",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen .log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .syslog_facility = "mail",
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .config_cache_size = 1024*1024,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen .version_ignore = FALSE,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .shutdown_clients = TRUE
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen};
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenconst struct setting_parser_info master_service_setting_parser_info = {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .module_name = "master",
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .defines = master_service_setting_defines,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen .defaults = &master_service_default_settings,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen .type_offset = (size_t)-1,
1cc7a6c6a986b972fdb7eac146f4ca8036aca4e6Timo Sirainen .struct_size = sizeof(struct master_service_settings),
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen .parent_offset = (size_t)-1
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen};
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic void ATTR_NORETURN
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenmaster_service_exec_config(struct master_service *service, bool preserve_home)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen{
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const char **conf_argv, *path, *const *paths, *binary_path;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen binary_path = service->argv[0];
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (*service->argv[0] == '/') {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* already have the path */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } else if (strchr(service->argv[0], '/') != NULL) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* relative to current directory */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen binary_path = t_abspath(service->argv[0]);
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen } else if ((path = getenv("PATH")) != NULL) {
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainen /* we have to find our executable from path */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen paths = t_strsplit(path, ":");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen for (; *paths != NULL; paths++) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen path = t_strconcat(*paths, "/", binary_path, NULL);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (access(path, X_OK) == 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen binary_path = path;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (!service->keep_environment)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen master_service_env_clean(preserve_home);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* @UNSAFE */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen conf_argv = t_new(const char *, 6 + (service->argc + 1) + 1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen conf_argv[0] = DOVECOT_CONFIG_BIN_PATH;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen conf_argv[1] = "-f";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen conf_argv[2] = t_strconcat("service=", service->name, NULL);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen conf_argv[3] = "-c";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen conf_argv[4] = service->config_path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen conf_argv[5] = "-e";
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen conf_argv[6] = binary_path;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen memcpy(conf_argv+7, service->argv + 1,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen (service->argc) * sizeof(conf_argv[0]));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen execv(conf_argv[0], (char **)conf_argv);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_fatal("execv(%s) failed: %m", conf_argv[0]);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
e597ab14b6fc01a602b35d26177d09643af8fed5Timo Sirainenstatic void
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenconfig_exec_fallback(struct master_service *service,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const struct master_service_settings_input *input)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *path;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct stat st;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (input->never_exec)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen path = input->config_path != NULL ? input->config_path :
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen master_service_get_config_path(service);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (stat(path, &st) == 0 &&
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* it's a file, not a socket/pipe */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen master_service_exec_config(service, input->preserve_home);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenmaster_service_open_config(struct master_service *service,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const struct master_service_settings_input *input,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen const char **path_r, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
66a164c358d14bb61de73288588ea65a6ba05113Timo Sirainen const char *path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *path_r = path = input->config_path != NULL ? input->config_path :
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen master_service_get_config_path(service);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen if (service->config_fd != -1 && input->config_path == NULL) {
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen /* use the already opened config socket */
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen fd = service->config_fd;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen service->config_fd = -1;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen return fd;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen }
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (service->config_path_is_default && input->config_path == NULL) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* first try to connect to the default config socket.
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen configuration may contain secrets, so in default config
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen this fails because the socket is 0600. it's useful for
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen developers though. :) */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fd >= 0) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen *path_r = DOVECOT_CONFIG_SOCKET_PATH;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen net_set_nonblock(fd, FALSE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen /* fallback to executing doveconf */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
e4d6ec308869598a3c32033b69993c523d53f10fTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fd = net_connect_unix_with_retries(path, 1000);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fd < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *error_r = t_strdup_printf("net_connect_unix(%s) failed: %m",
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen path);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen config_exec_fallback(service, input);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen return -1;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen net_set_nonblock(fd, FALSE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainenstatic void
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainenconfig_build_request(string_t *str,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const struct master_service_settings_input *input)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_append(str, "REQ");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (input->module != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_printfa(str, "\tmodule=%s", input->module);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (input->service != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_printfa(str, "\tservice=%s", input->service);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (input->username != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen str_printfa(str, "\tuser=%s", input->username);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (input->local_ip.family != 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_printfa(str, "\tlip=%s", net_ip2addr(&input->local_ip));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (input->remote_ip.family != 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_printfa(str, "\trip=%s", net_ip2addr(&input->remote_ip));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (input->local_host != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_printfa(str, "\tlhost=%s", input->local_host);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (input->remote_host != NULL)
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen str_printfa(str, "\tlhost=%s", input->remote_host);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_append_c(str, '\n');
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconfig_send_request(const struct master_service_settings_input *input,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int fd, const char *path, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen string_t *str;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str = t_str_new(128);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_append(str, CONFIG_HANDSHAKE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen config_build_request(str, input);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = write_full(fd, str_data(str), str_len(str));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *error_r = t_strdup_printf("write_full(%s) failed: %m", path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenmaster_service_apply_config_overrides(struct master_service *service,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen struct setting_parser_context *parser,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char *const *overrides;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen unsigned int i, count;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen overrides = array_get(&service->config_overrides, &count);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen for (i = 0; i < count; i++) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (settings_parse_line(parser, overrides[i]) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *error_r = t_strdup_printf(
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen "Invalid -o parameter %s: %s", overrides[i],
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen settings_parser_get_error(parser));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen settings_parse_set_key_expandeded(parser, service->set_pool,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen t_strcut(overrides[i], '='));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenconfig_read_reply_header(struct istream *istream, const char *path, pool_t pool,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const struct master_service_settings_input *input,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct master_service_settings_output *output_r,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char *line;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ssize_t ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen while ((ret = i_stream_read(istream)) > 0) {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen line = i_stream_next_line(istream);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (line != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret <= 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *error_r = istream->stream_errno != 0 ?
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen t_strdup_printf("read(%s) failed: %m", path) :
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen t_strdup_printf("read(%s) failed: EOF", path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char *const *arg = t_strsplit(line, "\t");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ARRAY_TYPE(const_string) services;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen p_array_init(&services, pool, 8);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen for (; *arg != NULL; arg++) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (strcmp(*arg, "service-uses-local") == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen output_r->service_uses_local = TRUE;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen else if (strcmp(*arg, "service-uses-remote") == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen output_r->service_uses_remote = TRUE;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (strcmp(*arg, "used-local") == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen output_r->used_local = TRUE;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen else if (strcmp(*arg, "used-remote") == 0)
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen output_r->used_remote = TRUE;
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen else if (strncmp(*arg, "service=", 8) == 0) {
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen const char *name = p_strdup(pool, *arg + 8);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen array_append(&services, &name, 1);
b866325bc5a7b922884cf10bb0316954c12ee75dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
b866325bc5a7b922884cf10bb0316954c12ee75dTimo Sirainen if (input->service == NULL) {
b866325bc5a7b922884cf10bb0316954c12ee75dTimo Sirainen (void)array_append_space(&services);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen output_r->specific_services = array_idx(&services, 0);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint master_service_settings_read(struct master_service *service,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const struct master_service_settings_input *input,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct master_service_settings_output *output_r,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ARRAY_DEFINE(all_roots, const struct setting_parser_info *);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const struct setting_parser_info *tmp_root;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen struct setting_parser_context *parser;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen struct istream *istream;
b866325bc5a7b922884cf10bb0316954c12ee75dTimo Sirainen const char *path = NULL, *error;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen void **sets;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen unsigned int i;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int ret, fd = -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen time_t now, timeout;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen memset(output_r, 0, sizeof(*output_r));
b866325bc5a7b922884cf10bb0316954c12ee75dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (getenv("DOVECONF_ENV") == NULL &&
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS) == 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fd = master_service_open_config(service, input, &path, error_r);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fd == -1)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
53895e43662b29a954d8f70bd2a27bafbdb4bbe8Timo Sirainen
53895e43662b29a954d8f70bd2a27bafbdb4bbe8Timo Sirainen if (config_send_request(input, fd, path, error_r) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen (void)close(fd);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen config_exec_fallback(service, input);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (service->set_pool != NULL) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (service->set_parser != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen settings_parser_deinit(&service->set_parser);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen p_clear(service->set_pool);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } else {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen service->set_pool =
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen pool_alloconly_create("master service settings", 8192);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (input->dyn_parsers != NULL) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen settings_parser_info_update(service->set_pool,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen input->dyn_parsers_parent,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen input->dyn_parsers);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen p_array_init(&all_roots, service->set_pool, 8);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen tmp_root = &master_service_setting_parser_info;
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen array_append(&all_roots, &tmp_root, 1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (input->roots != NULL) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen for (i = 0; input->roots[i] != NULL; i++)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen array_append(&all_roots, &input->roots[i], 1);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen }
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen parser = settings_parser_init_list(service->set_pool,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen array_idx(&all_roots, 0), array_count(&all_roots),
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (fd != -1) {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen istream = i_stream_create_fd(fd, (size_t)-1, FALSE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen now = time(NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen timeout = now + CONFIG_READ_TIMEOUT_SECS;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen do {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen alarm(timeout - now);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen ret = config_read_reply_header(istream, path,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen service->set_pool, input,
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen output_r, error_r);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (ret == 0) {
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen ret = settings_parse_stream_read(parser,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen istream);
8b3f557cda9023b87b183e364cb7f7c7b0906950Timo Sirainen if (ret < 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *error_r = settings_parser_get_error(parser);
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen alarm(0);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret <= 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
/* most likely timed out, but just in case some other
signal was delivered early check if we need to
continue */
now = time(NULL);
} while (now < timeout);
i_stream_unref(&istream);
if (ret != 0) {
if (ret > 0) {
*error_r = t_strdup_printf(
"Timeout reading config from %s", path);
}
(void)close(fd);
config_exec_fallback(service, input);
return -1;
}
if ((service->flags & MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN) != 0 &&
service->config_fd == -1 && input->config_path == NULL)
service->config_fd = fd;
else
(void)close(fd);
}
if (fd == -1 || service->keep_environment) {
if (settings_parse_environ(parser) < 0) {
*error_r = settings_parser_get_error(parser);
return -1;
}
}
if (array_is_created(&service->config_overrides)) {
if (master_service_apply_config_overrides(service, parser,
error_r) < 0)
return -1;
}
if (!settings_parser_check(parser, service->set_pool, &error)) {
*error_r = t_strdup_printf("Invalid settings: %s", error);
return -1;
}
sets = settings_parser_get_list(parser);
service->set = sets[0];
service->set_parser = parser;
if (service->set->version_ignore &&
(service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0) {
/* running standalone. we want to ignore plugin versions. */
service->version_string = NULL;
}
if (service->set->shutdown_clients)
master_service_set_die_with_master(master_service, TRUE);
/* if we change any settings afterwards, they're in expanded form.
especially all settings from userdb are already expanded. */
settings_parse_set_expanded(service->set_parser, TRUE);
return 0;
}
int master_service_settings_read_simple(struct master_service *service,
const struct setting_parser_info **roots,
const char **error_r)
{
struct master_service_settings_input input;
struct master_service_settings_output output;
memset(&input, 0, sizeof(input));
input.roots = roots;
input.module = service->name;
return master_service_settings_read(service, &input, &output, error_r);
}
pool_t master_service_settings_detach(struct master_service *service)
{
pool_t pool = service->set_pool;
settings_parser_deinit(&service->set_parser);
service->set_pool = NULL;
return pool;
}
const struct master_service_settings *
master_service_settings_get(struct master_service *service)
{
void **sets;
sets = settings_parser_get_list(service->set_parser);
return sets[0];
}
void **master_service_settings_get_others(struct master_service *service)
{
return settings_parser_get_list(service->set_parser) + 1;
}
int master_service_set(struct master_service *service, const char *line)
{
return settings_parse_line(service->set_parser, line);
}