service-process.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainenstatic void service_reopen_inet_listeners(struct service *service)
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen unsigned int i, count;
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen listeners = array_get(&service->listeners, &count);
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen for (i = 0; i < count; i++) {
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen if (!listeners[i]->reuse_port || listeners[i]->fd == -1)
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen if (service_listener_listen(listeners[i]) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* stdin/stdout is already redirected to /dev/null. Other master fds
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen should have been opened with fd_close_on_exec() so we don't have to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen worry about them.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen because the destination fd might be another one's source fd we have
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to be careful not to overwrite anything. dup() the fd when needed */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen listeners = array_get(&service->listeners, &count);
230ef558135f16a66b86cbe3762524eaa9ae9d81Timo Sirainen dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* nonblocking anvil fd must be the first one. anvil treats it
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen as the master's fd */
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* add listeners */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen for (i = 0; i < count; i++) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen str_append_tabescaped(listener_settings, listeners[i]->name);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen if (listeners[i]->type == SERVICE_LISTENER_INET) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen socket_listener_count, str_c(listener_settings)));
41ee23907b084da5baed459e35bccd5a33430419Timo Sirainen dup2_append(&dups, dev_null_fd, MASTER_ANVIL_FD);
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen dup2_append(&dups, service_anvil_global->blocking_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
0153cf542884f8f50d17a0d909c2da98a37dafdcTimo Sirainen dup2_append(&dups, service->master_dead_pipe_fd[1],
29f32cdcf44cda9688576bfdc7450a8a15e90e86Timo Sirainen dup2_append(&dups, global_master_dead_pipe_fd[1],
b955a1c1b6d466977d971c029a9305bee492f73cTimo Sirainen /* keep stderr as-is. this is especially important when
b955a1c1b6d466977d971c029a9305bee492f73cTimo Sirainen log_path=/dev/stderr, but might be helpful even in other
b955a1c1b6d466977d971c029a9305bee492f73cTimo Sirainen situations for logging startup errors */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set log file to stderr. dup2() here immediately so that
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen we can set up logging to it without causing any log messages
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to be lost. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure we don't leak syslog fd. try to do it as late as possible,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen but also before dup2()s in case syslog fd is one of them. */
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen i_fatal("service(%s): dup2s failed", service->set->name);
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.privileged_gid = service->privileged_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen /* drop trailing / if it exists */
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen rset.chroot_dir = t_strndup(rset.chroot_dir, len-1);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen disallow_root = service->type == SERVICE_TYPE_LOGIN;
9e291f6a7ca67b86d1d65a730ffb71fb9a334fb0Timo Sirainenstatic void service_process_setup_config_environment(struct service *service)
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen const struct master_service_settings *set = service->list->service_set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* give the log's configuration directly, so it won't depend
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen on config process */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("LOG_PATH=", set->log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("INFO_LOG_PATH=", set->info_log_path, NULL));
f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227eaTimo Sirainen env_put(t_strconcat("DEBUG_LOG_PATH=", set->debug_log_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("LOG_TIMESTAMP=", set->log_timestamp, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("SYSLOG_FACILITY=", set->syslog_facility, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen services_get_config_socket_path(service->list), NULL));
28482afc8139462ff9bcc6cedc4936129e8763efTimo Sirainenservice_process_setup_environment(struct service *service, unsigned int uid,
9e291f6a7ca67b86d1d65a730ffb71fb9a334fb0Timo Sirainen service_process_setup_config_environment(service);
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u",
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen env_put(t_strdup_printf(MASTER_PROCESS_LIMIT_ENV"=%u",
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen env_put(t_strdup_printf(MASTER_PROCESS_MIN_AVAIL_ENV"=%u",
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_IDLE_KILL_ENV"=%u",
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_COUNT_ENV"=%u",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_UID_ENV"=%u", uid));
a8aec60b5359e5ea7fc7a9464217ae3626df8785Timo Sirainen env_put(t_strdup_printf(MY_HOSTNAME_ENV"=%s", my_hostname));
28482afc8139462ff9bcc6cedc4936129e8763efTimo Sirainen env_put(t_strdup_printf(MY_HOSTDOMAIN_ENV"=%s", hostdomain));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->master_set->version_ignore)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(MASTER_DOVECOT_VERSION_ENV"="PACKAGE_VERSION);
0547a828ee9647fc5fd2e359b145774740a697feTimo Sirainen if (ssl_manual_key_password != NULL && service->have_inet_listeners) {
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen /* manually given SSL password. give it only to services
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen that have inet listeners. */
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen env_put(t_strconcat(MASTER_SSL_KEY_PASSWORD_ENV"=",
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen service->list->service_set->log_debug, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_status_timeout(struct service_process *process)
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen "Initial status notification not received in %d "
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen "seconds, killing the process",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(process->service, "kill(%s, SIGKILL) failed: %m",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct service_process *service_process_create(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen static unsigned int uid_counter = 0;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen /* throttling service, don't create new processes */
e5097d2c8efecdd274272b222cf2b30a8ae4ca2aTimo Sirainen /* these services are being destroyed, no point in creating
e5097d2c8efecdd274272b222cf2b30a8ae4ca2aTimo Sirainen new processes now */
28482afc8139462ff9bcc6cedc4936129e8763efTimo Sirainen /* look this up before fork()ing so that it gets cached for all the
28482afc8139462ff9bcc6cedc4936129e8763efTimo Sirainen future lookups. */
939f758ca239c53a60dae89e70ccdecd92072c5bTimo Sirainen limit_str = t_strdup_printf(" (ulimit -u %llu reached?)",
939f758ca239c53a60dae89e70ccdecd92072c5bTimo Sirainen (unsigned long long)limit);
939f758ca239c53a60dae89e70ccdecd92072c5bTimo Sirainen service_error(service, "fork() failed: %m%s", limit_str);
28482afc8139462ff9bcc6cedc4936129e8763efTimo Sirainen service_process_setup_environment(service, uid, hostdomain);
46ad586b6d5f4c3e3f46728199e81ddd63225fb3Timo Sirainen i_assert(hash_table_lookup(service_pids, POINTER_CAST(pid)) == NULL);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000,
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen process->available_count = service->client_limit;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(service_pids, POINTER_CAST(process->pid), process);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (service->type == SERVICE_TYPE_ANVIL && process_forked)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_destroy(struct service_process *process)
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen struct service_list *service_list = service->list;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_remove(service_pids, POINTER_CAST(process->pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->process_avail <= service->process_count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service_process_notify_add(service->list->log_byes, process);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->process_count < service->process_limit &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_ref(struct service_process *process)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenvoid service_process_unref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenget_exit_status_message(struct service *service, enum fatal_exit_status status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Can't open log file";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Can't write to log file";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Internal logging error";
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(str, " (service %s { vsz_limit=%"PRIuUOFF_T" MB }, "
077ab4470660b791c2b76eb4bb5663bbafc8177fTimo Sirainen "you may need to increase it)",
7fc91e27999996932fb8094a6d566466db2167dbTimo Sirainen str_append(str, " - set CORE_OUTOFMEM=1 environment to get core dump");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "exec() failed";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Fatal failure";
129db31de1780783a175633eba5811e44c361a81Timo Sirainenlog_coredump(struct service *service, string_t *str, int status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (signum != SIGABRT && signum != SIGSEGV && signum != SIGBUS)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* let's try to figure out why we didn't get a core dump */
114162093a3eb36c23a4ce4d4f2a43541dc18cc2Timo Sirainen if (!service->set->drop_priv_before_exec && service->uid != 0) {
ca502ca792708238ac2c23481c3bf94eda1f743fTimo Sirainen str_printfa(str, " (core not dumped - set service %s "
ca502ca792708238ac2c23481c3bf94eda1f743fTimo Sirainen "{ drop_priv_before_exec=yes })",
114162093a3eb36c23a4ce4d4f2a43541dc18cc2Timo Sirainen if (*service->set->privileged_group != '\0' && service->uid != 0) {
ca502ca792708238ac2c23481c3bf94eda1f743fTimo Sirainen str_printfa(str, " (core not dumped - service %s "
ca502ca792708238ac2c23481c3bf94eda1f743fTimo Sirainen "{ privileged_group } prevented it)",
dfcc56dc6c485fe45a3fa18325f047bfaae65019Timo Sirainen str_printfa(str, " (core not dumped - add -D parameter to "
dfcc56dc6c485fe45a3fa18325f047bfaae65019Timo Sirainen "service %s { executable }", service->set->name);
e1c08b1d9ba29f55462914451b5d5d6959ebd144Timo Sirainen str_printfa(str, " (core not dumped - try to clear "
e1c08b1d9ba29f55462914451b5d5d6959ebd144Timo Sirainen "service %s { chroot = } )", service->set->name);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenservice_process_get_status_error(string_t *str, struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *msg;
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen str_printfa(str, "service(%s): child %s ", service->set->name,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, "killed with signal %d", WTERMSIG(status));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, "died with status %d", status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, "returned error %d", status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen msg = get_exit_status_message(service, status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_log(struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* log it via the log process in charge of handling
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen this process's logging */
800fc30be46bc6f8380f6de04aea7c19ea839ddfTimo Sirainen default_fatal ? "DEFAULT-FATAL" : "FATAL", str);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (write(process->service->list->master_log_fd[1],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_log_status_error(struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* fast path */
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen service_process_get_status_error(str, process, status,