<commit_before>/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "abspath.h"
#include "istream.h"
#include "write-full.h"
#include "str.h"
#include "execv-const.h"
#include "settings-parser.h"
#include "master-service-private.h"
#include "master-service-settings.h"

#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>

#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
#define DOVECOT_CONFIG_SOCKET_PATH PKG_RUNDIR"/config"

#define CONFIG_READ_TIMEOUT_SECS 10
#define CONFIG_HANDSHAKE "VERSION\tconfig\t2\t0\n"

#undef DEF
#define DEF(type, name) \
	{ type, #name, offsetof(struct master_service_settings, name), NULL }

static const struct setting_define master_service_setting_defines[] = {
	DEF(SET_STR, log_path),
	DEF(SET_STR, info_log_path),
	DEF(SET_STR, debug_log_path),
	DEF(SET_STR, log_timestamp),
	DEF(SET_STR, syslog_facility),
	DEF(SET_SIZE, config_cache_size),
	DEF(SET_BOOL, version_ignore),
	DEF(SET_BOOL, shutdown_clients),

	SETTING_DEFINE_LIST_END
};

static const struct master_service_settings master_service_default_settings = {
	.log_path = "",
	.info_log_path = "",
	.debug_log_path = "",
	.log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT,
	.syslog_facility = "mail",
	.config_cache_size = 1024*1024,
	.version_ignore = FALSE,
	.shutdown_clients = TRUE
};

const struct setting_parser_info master_service_setting_parser_info = {
	.module_name = "master",
	.defines = master_service_setting_defines,
	.defaults = &master_service_default_settings,

	.type_offset = (size_t)-1,
	.struct_size = sizeof(struct master_service_settings),

	.parent_offset = (size_t)-1
};

static void ATTR_NORETURN
master_service_exec_config(struct master_service *service,
			   const struct master_service_settings_input *input)
{
	const char **conf_argv, *binary_path = service->argv[0];

	(void)t_binary_abspath(&binary_path);

	if (!service->keep_environment)
		master_service_env_clean(input->preserve_home);

	/* @UNSAFE */
	conf_argv = t_new(const char *, 8 + (service->argc + 1) + 1);
	conf_argv[0] = DOVECOT_CONFIG_BIN_PATH;
	conf_argv[1] = "-f";
	conf_argv[2] = t_strconcat("service=", service->name, NULL);
	conf_argv[3] = "-m";
	conf_argv[4] = input->module == NULL ? "" : input->module;
	conf_argv[5] = "-c";
	conf_argv[6] = service->config_path;
	conf_argv[7] = "-e";
	conf_argv[8] = binary_path;
	memcpy(conf_argv+9, service->argv + 1,
	       (service->argc) * sizeof(conf_argv[0]));
	execv_const(conf_argv[0], conf_argv);
}

static void
config_exec_fallback(struct master_service *service,
		     const struct master_service_settings_input *input)
{
	const char *path;
	struct stat st;

	if (input->never_exec)
		return;

	path = input->config_path != NULL ? input->config_path :
		master_service_get_config_path(service);
	if (stat(path, &st) == 0 &&
	    !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
		/* it's a file, not a socket/pipe */
		master_service_exec_config(service, input);
	}
}

static int
master_service_open_config(struct master_service *service,
			   const struct master_service_settings_input *input,
			   const char **path_r, const char **error_r)
{
	const char *path;
	int fd;

	*path_r = path = input->config_path != NULL ? input->config_path :
		master_service_get_config_path(service);

	if (service->config_fd != -1 && input->config_path == NULL) {
		/* use the already opened config socket */
		fd = service->config_fd;
		service->config_fd = -1;
		return fd;
	}

	if (service->config_path_is_default && input->config_path == NULL) {
		/* first try to connect to the default config socket.
		   configuration may contain secrets, so in default config
		   this fails because the socket is 0600. it's useful for
		   developers though. :) */
		fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH);
		if (fd >= 0) {
			*path_r = DOVECOT_CONFIG_SOCKET_PATH;
			net_set_nonblock(fd, FALSE);
			return fd;
		}
		/* fallback to executing doveconf */
	}

	fd = net_connect_unix_with_retries(path, 1000);
	if (fd < 0) {
		*error_r = t_strdup_printf("net_connect_unix(%s) failed: %m",
					   path);
		config_exec_fallback(service, input);<commit_msg>lib-master: If config path isn't a socket, don't try to connect() to it. This avoids some SELinux errors.<commit_after>/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "abspath.h"
#include "istream.h"
#include "write-full.h"
#include "str.h"
#include "execv-const.h"
#include "settings-parser.h"
#include "master-service-private.h"
#include "master-service-settings.h"

#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>

#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
#define DOVECOT_CONFIG_SOCKET_PATH PKG_RUNDIR"/config"

#define CONFIG_READ_TIMEOUT_SECS 10
#define CONFIG_HANDSHAKE "VERSION\tconfig\t2\t0\n"

#undef DEF
#define DEF(type, name) \
	{ type, #name, offsetof(struct master_service_settings, name), NULL }

static const struct setting_define master_service_setting_defines[] = {
	DEF(SET_STR, log_path),
	DEF(SET_STR, info_log_path),
	DEF(SET_STR, debug_log_path),
	DEF(SET_STR, log_timestamp),
	DEF(SET_STR, syslog_facility),
	DEF(SET_SIZE, config_cache_size),
	DEF(SET_BOOL, version_ignore),
	DEF(SET_BOOL, shutdown_clients),

	SETTING_DEFINE_LIST_END
};

static const struct master_service_settings master_service_default_settings = {
	.log_path = "",
	.info_log_path = "",
	.debug_log_path = "",
	.log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT,
	.syslog_facility = "mail",
	.config_cache_size = 1024*1024,
	.version_ignore = FALSE,
	.shutdown_clients = TRUE
};

const struct setting_parser_info master_service_setting_parser_info = {
	.module_name = "master",
	.defines = master_service_setting_defines,
	.defaults = &master_service_default_settings,

	.type_offset = (size_t)-1,
	.struct_size = sizeof(struct master_service_settings),

	.parent_offset = (size_t)-1
};

static void ATTR_NORETURN
master_service_exec_config(struct master_service *service,
			   const struct master_service_settings_input *input)
{
	const char **conf_argv, *binary_path = service->argv[0];

	(void)t_binary_abspath(&binary_path);

	if (!service->keep_environment)
		master_service_env_clean(input->preserve_home);

	/* @UNSAFE */
	conf_argv = t_new(const char *, 8 + (service->argc + 1) + 1);
	conf_argv[0] = DOVECOT_CONFIG_BIN_PATH;
	conf_argv[1] = "-f";
	conf_argv[2] = t_strconcat("service=", service->name, NULL);
	conf_argv[3] = "-m";
	conf_argv[4] = input->module == NULL ? "" : input->module;
	conf_argv[5] = "-c";
	conf_argv[6] = service->config_path;
	conf_argv[7] = "-e";
	conf_argv[8] = binary_path;
	memcpy(conf_argv+9, service->argv + 1,
	       (service->argc) * sizeof(conf_argv[0]));
	execv_const(conf_argv[0], conf_argv);
}

static void
config_exec_fallback(struct master_service *service,
		     const struct master_service_settings_input *input)
{
	const char *path;
	struct stat st;

	if (input->never_exec)
		return;

	path = input->config_path != NULL ? input->config_path :
		master_service_get_config_path(service);
	if (stat(path, &st) == 0 &&
	    !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
		/* it's a file, not a socket/pipe */
		master_service_exec_config(service, input);
	}
}

static int
master_service_open_config(struct master_service *service,
			   const struct master_service_settings_input *input,
			   const char **path_r, const char **error_r)
{
	struct stat st;
	const char *path;
	int fd;

	*path_r = path = input->config_path != NULL ? input->config_path :
		master_service_get_config_path(service);

	if (service->config_fd != -1 && input->config_path == NULL) {
		/* use the already opened config socket */
		fd = service->config_fd;
		service->config_fd = -1;
		return fd;
	}

	if (service->config_path_is_default && input->config_path == NULL) {
		/* first try to connect to the default config socket.
		   configuration may contain secrets, so in default config
		   this fails because the socket is 0600. it's useful for
		   developers though. :) */
		fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH);
		if (fd >= 0) {
			*path_r = DOVECOT_CONFIG_SOCKET_PATH;
			net_set_nonblock(fd, FALSE);
			return fd;
		}
		/* fallback to executing doveconf */
	}

	if (stat(path, &st) == 0 &&
	    !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
		/* it's not an UNIX socket, don't even try to connect */
		fd = -1;
		errno = ENOTSOCK;
	} else {
		fd = net_connect_unix_with_retries(path, 1000);
	}
	if (fd < 0) {
		*error_r = t_strdup_printf("net_connect_unix(%s) failed: %m",
					   path);
		config_exec_fallback(service, input);
{'fraction_non_alphanumeric': 0.1312378111735689, 'fraction_numerical': 0.012160146839509006, 'mean_word_length': 4.967145790554415, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7474211', 'n_tokens_mistral': 3385, 'n_tokens_neox': 3181, 'n_words': 676}