bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen#define DOVECOT_CONFIG_SOCKET_PATH PKG_RUNDIR"/config"
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen#define CONFIG_HANDSHAKE "VERSION\tconfig\t2\t0\n"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { type, #name, offsetof(struct master_service_settings, name), NULL }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenmaster_service_settings_check(void *_set, pool_t pool, const char **error_r);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstatic const struct setting_define master_service_setting_defines[] = {
8d7c78157f1acd25aa989cf02d9518a85d2c89d4Timo Sirainen/* <settings checks> */
8d7c78157f1acd25aa989cf02d9518a85d2c89d4Timo Sirainen/* </settings checks> */
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstatic const struct master_service_settings master_service_default_settings = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT,
8d7c78157f1acd25aa989cf02d9518a85d2c89d4Timo Sirainen .import_environment = "TZ CORE_OUTOFMEM CORE_ERROR" ENV_SYSTEMD ENV_GDB,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenconst struct setting_parser_info master_service_setting_parser_info = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .struct_size = sizeof(struct master_service_settings),
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen/* <settings checks> */
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainenint master_service_log_debug_parse(struct event_filter *filter, const char *str,
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen const char **error_r)
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen /* FIXME: we should support more complicated filters */
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen const char *const *args = t_strsplit_spaces(str, " ");
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen for (unsigned int i = 0; args[i] != NULL; i++) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainenmaster_service_settings_check(void *_set, pool_t pool ATTR_UNUSED,
2eed51b45a58562cc89d49c5f572f47d83390f23Timo Sirainen const char **error_r)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* default to syslog logging */
2eed51b45a58562cc89d49c5f572f47d83390f23Timo Sirainen if (!syslog_facility_find(set->syslog_facility, &facility)) {
2eed51b45a58562cc89d49c5f572f47d83390f23Timo Sirainen *error_r = t_strdup_printf("Unknown syslog_facility: %s",
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen struct event_filter *filter = event_filter_create();
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen if (master_service_log_debug_parse(filter, set->log_debug, &error) < 0) {
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen *error_r = t_strdup_printf("Invalid log_debug: %s", error);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen/* </settings checks> */
e75ff6a1854ee9befb751d14023bd5fa756fbf3bTimo Sirainenmaster_service_exec_config(struct master_service *service,
e75ff6a1854ee9befb751d14023bd5fa756fbf3bTimo Sirainen const struct master_service_settings_input *input)
e1237f7e7f978e23c86cf51b69742291c316f75cTimo Sirainen const char **conf_argv, *binary_path = service->argv[0];
d764f67e463b5d8ea3dc9f5c932bf83d76cad1f0Martti Rannanjärvi if (!t_binary_abspath(&binary_path, &error)) {
d764f67e463b5d8ea3dc9f5c932bf83d76cad1f0Martti Rannanjärvi i_fatal("t_binary_abspath(%s) failed: %s", binary_path, error);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen if (!service->keep_environment && !input->preserve_environment) {
9f41af1f09df00977a598008a15672dbdc2c3b72Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
ed6b37eeec4c20354a871ad5f4dc0a97f769d37eTimo Sirainen master_service_import_environment("LOG_STDERR_TIMESTAMP");
de266e09d27b44f0c51d67aea6a26fb1640f3290Timo Sirainen /* doveconf empties the environment before exec()ing us back
de266e09d27b44f0c51d67aea6a26fb1640f3290Timo Sirainen if DOVECOT_PRESERVE_ENVS is set, so make sure it is. */
de266e09d27b44f0c51d67aea6a26fb1640f3290Timo Sirainen if (getenv(DOVECOT_PRESERVE_ENVS_ENV) == NULL)
de266e09d27b44f0c51d67aea6a26fb1640f3290Timo Sirainen /* make sure doveconf doesn't remove any environment */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* @UNSAFE */
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen argv_max_count = 11 + (service->argc + 1) + 1;
8d173ad4d740a8a1c584328718325feea62201c8Timo Sirainen conf_argv = t_new(const char *, argv_max_count);
cf89092dff3defce94f1860a04b3ce8bfaf4a712Timo Sirainen conf_argv[i++] = t_strconcat("service=", input->service, NULL);
4a7863c531a27498830004ca2ead2eb53812ed79Timo Sirainenconfig_exec_fallback(struct master_service *service,
4a7863c531a27498830004ca2ead2eb53812ed79Timo Sirainen const struct master_service_settings_input *input)
4a7863c531a27498830004ca2ead2eb53812ed79Timo Sirainen path = input->config_path != NULL ? input->config_path :
4a7863c531a27498830004ca2ead2eb53812ed79Timo Sirainen !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
4a7863c531a27498830004ca2ead2eb53812ed79Timo Sirainen /* it's a file, not a socket/pipe */
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainenmaster_service_open_config(struct master_service *service,
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainen const struct master_service_settings_input *input,
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen *path_r = path = input->config_path != NULL ? input->config_path :
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen if (service->config_fd != -1 && input->config_path == NULL &&
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen /* use the already opened config socket */
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen /* first try to connect to the default config socket.
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen configuration may contain secrets, so in default config
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen this fails because the socket is 0600. it's useful for
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen developers though. :) */
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH);
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen /* fallback to executing doveconf */
73fed8af5e20022bdef8620bb074507755ec2c5eTimo Sirainen *error_r = errno == EACCES ? eacces_error_get("stat", path) :
73fed8af5e20022bdef8620bb074507755ec2c5eTimo Sirainen if (!S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
5ea5c79ca3f6012095bd5e9b2251e6dd5f614a8dTimo Sirainen /* it's not an UNIX socket, don't even try to connect */
5ea5c79ca3f6012095bd5e9b2251e6dd5f614a8dTimo Sirainen fd = net_connect_unix_with_retries(path, 1000);
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen *error_r = t_strdup_printf("net_connect_unix(%s) failed: %m",
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainenconfig_build_request(struct master_service *service, string_t *str,
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen const struct master_service_settings_input *input)
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen str_printfa(str, "\tmodule=%s", input->module);
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen str_printfa(str, "\tservice=%s", input->service);
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen str_printfa(str, "\tuser=%s", input->username);
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen str_printfa(str, "\tlip=%s", net_ip2addr(&input->local_ip));
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen str_printfa(str, "\trip=%s", net_ip2addr(&input->remote_ip));
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen str_printfa(str, "\tlname=%s", input->local_name);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainenconfig_send_request(struct master_service *service,
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen const struct master_service_settings_input *input,
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen int fd, const char *path, const char **error_r)
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainen ret = write_full(fd, str_data(str), str_len(str));
a03b4fe1a887d187d0dbcd961e9d5127f7c5bf2aTimo Sirainen *error_r = t_strdup_printf("write_full(%s) failed: %m", path);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainenmaster_service_apply_config_overrides(struct master_service *service,
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen const char **error_r)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen overrides = array_get(&service->config_overrides, &count);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen for (i = 0; i < count; i++) {
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (settings_parse_line(parser, overrides[i]) < 0) {
29357a858c79d8502ac83ab3b5425b5ffb64aa2eJosh Soref settings_parse_set_key_expanded(parser, service->set_pool,
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainenconfig_read_reply_header(struct istream *istream, const char *path, pool_t pool,
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen const struct master_service_settings_input *input,
a7a316bc6cbd7c89bf01ac091a2e9fc2d514f1a0Timo Sirainen struct master_service_settings_output *output_r,
a7a316bc6cbd7c89bf01ac091a2e9fc2d514f1a0Timo Sirainen const char **error_r)
a7a316bc6cbd7c89bf01ac091a2e9fc2d514f1a0Timo Sirainen t_strdup_printf("read(%s) failed: EOF", path);
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen const char *const *arg = t_strsplit_tabescaped(line);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen else if (strcmp(*arg, "service-uses-remote") == 0)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen output_r->specific_services = array_idx(&services, 0);
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainenvoid master_service_config_socket_try_open(struct master_service *service)
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen /* we'll get here before command line parameters have been parsed,
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen so -O, -c and -i parameters haven't been handled yet at this point.
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen this means we could end up opening config socket connection
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen unnecessarily, but this isn't a problem. we'll just have to
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen ignore it later on. (unfortunately there isn't a master_service_*()
553f96fdbff9f70e7b5d2261ae61b9ddf5156414Timo Sirainen call where this function would be better called.) */
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS) != 0)
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen fd = master_service_open_config(service, &input, &path, &error);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint master_service_settings_read(struct master_service *service,
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainen const struct master_service_settings_input *input,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct master_service_settings_output *output_r,
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainen const char **error_r)
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(const struct setting_parser_info *) all_roots;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i;
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen (service->flags & MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS) == 0) {
1f73636296eb5ac856f36a08543fdc61983f1555Timo Sirainen fd = master_service_open_config(service, input,
1f73636296eb5ac856f36a08543fdc61983f1555Timo Sirainen /* config process died, retry connecting */
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen pool_alloconly_create("master service settings", 16384);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p_array_init(&all_roots, service->set_pool, 8);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen tmp_root = &master_service_setting_parser_info;
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen tmp_root = &master_service_ssl_setting_parser_info;
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainen array_append(&all_roots, &input->roots[i], 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen parser = settings_parser_init_list(service->set_pool,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_idx(&all_roots, 0), array_count(&all_roots),
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi istream = i_stream_create_fd(fd, (size_t)-1);
27ca0e561c70933da8834e57f967dee9b41896baTimo Sirainen /* most likely timed out, but just in case some other
27ca0e561c70933da8834e57f967dee9b41896baTimo Sirainen signal was delivered early check if we need to
1f9d1bedae25d86f26c239055c5487499dfeeb58Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN) != 0 &&
1f9d1bedae25d86f26c239055c5487499dfeeb58Timo Sirainen service->config_fd == -1 && input->config_path == NULL)
497e3c244905f2019499eb42bfef11e203bf3f52Timo Sirainen if (use_environment || service->keep_environment) {
a814eff9aada6c78d39fa09682a78d950993f381Martti Rannanjärvi *error_r = t_strdup(settings_parser_get_error(parser));
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (array_is_created(&service->config_overrides)) {
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (master_service_apply_config_overrides(service, parser,
8c4b2e0734326ef8e534f25e8ee78ace1fc22d15Timo Sirainen if (!settings_parser_check(parser, service->set_pool, &error)) {
a814eff9aada6c78d39fa09682a78d950993f381Martti Rannanjärvi *error_r = t_strdup_printf("Invalid settings: %s", error);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* running standalone. we want to ignore plugin versions. */
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_SEND_STATS) != 0) {
5343822b9b61907ce16993da795d08998cb6fa14Timo Sirainen /* When running standalone (e.g. doveadm) try to connect to the
5343822b9b61907ce16993da795d08998cb6fa14Timo Sirainen stats socket, but don't log an error if it's not running.
5343822b9b61907ce16993da795d08998cb6fa14Timo Sirainen It may be intentional. */
5343822b9b61907ce16993da795d08998cb6fa14Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0;
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen master_service_init_stats_client(service, silent_notfound_errors);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen master_service_set_die_with_master(master_service, TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* if we change any settings afterwards, they're in expanded form.
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen especially all settings from userdb are already expanded. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen settings_parse_set_expanded(service->set_parser, TRUE);
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainenint master_service_settings_read_simple(struct master_service *service,
44aac2d461b4cb8e05e8c07f2f209372997a8719Timo Sirainen const char **error_r)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return master_service_settings_read(service, &input, &output, error_r);
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainenpool_t master_service_settings_detach(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaster_service_settings_get(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sets = settings_parser_get_list(service->set_parser);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid **master_service_settings_get_others(struct master_service *service)
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen return master_service_settings_parser_get_others(service,
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainenvoid **master_service_settings_parser_get_others(struct master_service *service,
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen const struct setting_parser_context *set_parser)
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen return settings_parser_get_list(set_parser) + 1 +
35d87d75ac84ac6aee86c3a1b0dccf627b21457fTimo Sirainenmaster_service_get_settings_parser(struct master_service *service)
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainenint master_service_set(struct master_service *service, const char *line)
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen return settings_parse_line(service->set_parser, line);
61f45f55439e542d8645d1851cb56ffc36cd10f6Timo Sirainenbool master_service_set_has_config_override(struct master_service *service,
61f45f55439e542d8645d1851cb56ffc36cd10f6Timo Sirainen const char *key)
61f45f55439e542d8645d1851cb56ffc36cd10f6Timo Sirainen if (!array_is_created(&service->config_overrides))
61f45f55439e542d8645d1851cb56ffc36cd10f6Timo Sirainen key_root = settings_parse_unalias(service->set_parser, key);
61f45f55439e542d8645d1851cb56ffc36cd10f6Timo Sirainen array_foreach(&service->config_overrides, override) {