service-process.c revision 6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "common.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "array.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "aqueue.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "ioloop.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "istream.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "ostream.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "write-full.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "base64.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "hash.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "str.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "hostpid.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "env-util.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "fd-close-on-exec.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "restrict-access.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "master-service-settings.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "dup2-array.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "service.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "service-log.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "service-auth-server.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "service-auth-source.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "service-process-notify.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include "service-process.h"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include <stdlib.h>
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include <unistd.h>
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include <fcntl.h>
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include <syslog.h>
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include <signal.h>
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#include <sys/wait.h>
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherservice_dup_fds(struct service *service, int auth_fd, int std_fd,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher bool give_anvil_fd)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct service_listener *const *listeners;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher ARRAY_TYPE(dup2) dups;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher unsigned int i, count, n = 0, socket_listener_count, ssl_socket_count;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* stdin/stdout is already redirected to /dev/null. Other master fds
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher should have been opened with fd_close_on_exec() so we don't have to
681742138b2afbbefa7f14de937beb438409208eSimo Sorce worry about them.
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher because the destination fd might be another one's source fd we have
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher to be careful not to overwrite anything. dup() the fd when needed */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher socket_listener_count = 0;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher listeners = array_get(&service->listeners, &count);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher t_array_init(&dups, count + 10);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (service->type) {
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce case SERVICE_TYPE_LOG:
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce i_assert(n == 0);
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce services_log_dup2(&dups, service->list, MASTER_LISTEN_FD_FIRST,
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce &socket_listener_count);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher n += socket_listener_count;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_ANVIL:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* nonblocking anvil fd must be the first one. anvil treats it
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher as the master's fd */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, service->list->nonblocking_anvil_fd[0],
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher MASTER_LISTEN_FD_FIRST + n++);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, service->list->blocking_anvil_fd[0],
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher MASTER_LISTEN_FD_FIRST + n++);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher socket_listener_count += 2;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher default:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* first add non-ssl listeners */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher for (i = 0; i < count; i++) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (listeners[i]->fd != -1 &&
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce (listeners[i]->type != SERVICE_LISTENER_INET ||
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce !listeners[i]->set.inetset.set->ssl)) {
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce dup2_append(&dups, listeners[i]->fd,
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce MASTER_LISTEN_FD_FIRST + n);
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce n++; socket_listener_count++;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* then ssl-listeners */
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek ssl_socket_count = 0;
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce for (i = 0; i < count; i++) {
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce if (listeners[i]->fd != -1 &&
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce listeners[i]->type == SERVICE_LISTENER_INET &&
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce listeners[i]->set.inetset.set->ssl) {
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce dup2_append(&dups, listeners[i]->fd,
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce MASTER_LISTEN_FD_FIRST + n);
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce n++; socket_listener_count++;
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce ssl_socket_count++;
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce if (!give_anvil_fd)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, null_fd, MASTER_ANVIL_FD);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher else {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, service->list->blocking_anvil_fd[1],
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher MASTER_ANVIL_FD);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (service->type) {
681742138b2afbbefa7f14de937beb438409208eSimo Sorce case SERVICE_TYPE_AUTH_SOURCE:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SERVER:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(auth_fd != -1);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, auth_fd, MASTER_AUTH_FD);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strdup_printf("MASTER_AUTH_FD=%d", MASTER_AUTH_FD));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher default:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(auth_fd == -1);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, null_fd, MASTER_AUTH_FD);
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce break;
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce }
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce if (std_fd != -1) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, std_fd, STDIN_FILENO);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, std_fd, STDOUT_FILENO);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put("LOGGED_IN=1");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (service->type != SERVICE_TYPE_LOG) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* set log file to stderr. dup2() here immediately so that
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher we can set up logging to it without causing any log messages
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher to be lost. */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(service->log_fd[1] != -1);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put("LOG_SERVICE=1");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_fatal("dup2(log fd) failed: %m");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_set_failure_internal();
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher } else {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dup2_append(&dups, null_fd, STDERR_FILENO);
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce }
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce /* make sure we don't leak syslog fd. try to do it as late as possible,
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce but also before dup2()s in case syslog fd is one of them. */
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce closelog();
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (dup2_array(&dups) < 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_error(service, "dup2s failed");
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce env_put(t_strdup_printf("SSL_SOCKET_COUNT=%d", ssl_socket_count));
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce}
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce
fd555d130dc733509347fa096a2cb858b014a196Simo Sorcestatic int validate_uid_gid(struct master_settings *set, uid_t uid, gid_t gid,
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce const char *user)
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce{
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce if (uid == 0) {
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce i_error("Logins with UID 0 not permitted (user %s)", user);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return FALSE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
fd555d130dc733509347fa096a2cb858b014a196Simo Sorce
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (uid < (uid_t)set->first_valid_uid ||
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("Logins with UID %s (user %s) not permitted "
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher "(see first_valid_uid in config file)",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dec2str(uid), user);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return FALSE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek if (gid < (gid_t)set->first_valid_gid ||
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (set->last_valid_gid != 0 && gid > (gid_t)set->last_valid_gid)) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("Logins for users with primary group ID %s (user %s) "
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher "not permitted (see first_valid_gid in config file).",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dec2str(gid), user);
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher return FALSE;
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return TRUE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void auth_args_apply(const char *const *args,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct restrict_access_settings *rset,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char **home)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char *key, *value;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher string_t *expanded_vars;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher expanded_vars = t_str_new(128);
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek str_append(expanded_vars, "VARS_EXPANDED=");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher for (; *args != NULL; args++) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (strncmp(*args, "uid=", 4) == 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset->uid = (uid_t)strtoul(*args + 4, NULL, 10);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher else if (strncmp(*args, "gid=", 4) == 0)
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek rset->gid = (gid_t)strtoul(*args + 4, NULL, 10);
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek else if (strncmp(*args, "home=", 5) == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher *home = *args + 5;
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek env_put(t_strconcat("HOME=", *args + 5, NULL));
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek } else if (strncmp(*args, "chroot=", 7) == 0)
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek rset->chroot_dir = *args + 7;
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek else if (strncmp(*args, "system_groups_user=", 19) == 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset->system_groups_user = *args + 19;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher else if (strncmp(*args, "mail_access_groups=", 19) == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset->extra_groups =
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset->extra_groups == NULL ? *args + 19 :
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher t_strconcat(*args + 19, ",",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset->extra_groups, NULL);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher } else {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* unknown, set as environment */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher value = strchr(*args, '=');
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (value == NULL) {
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek /* boolean */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher key = *args;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher value = "=1";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher } else {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher key = t_strdup_until(*args, value);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (strcmp(key, "mail") == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* FIXME: kind of ugly to have it
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher here.. */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher key = "mail_location";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append(expanded_vars, key);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append_c(expanded_vars, ' ');
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat(t_str_ucase(key), value, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(str_c(expanded_vars));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void auth_success_write(void)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher int fd;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (auth_success_written)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher fd = creat(AUTH_SUCCESS_PATH, 0666);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (fd == -1)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("creat(%s) failed: %m", AUTH_SUCCESS_PATH);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher else
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (void)close(fd);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher auth_success_written = TRUE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void drop_privileges(struct service *service,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char *const *auth_args)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct master_settings *master_set = service->set->master_set;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct restrict_access_settings rset;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char *user, *home = NULL;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher bool disallow_root;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher restrict_access_init(&rset);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.uid = service->uid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.gid = service->gid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.privileged_gid = service->privileged_gid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->set->chroot;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.extra_groups = service->extra_gids;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (auth_args == NULL) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* non-authenticating service. don't use *_valid_gid checks */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher } else {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(auth_args[0] != NULL);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.first_valid_gid = master_set->first_valid_gid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher rset.last_valid_gid = master_set->last_valid_gid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher user = auth_args[0];
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat("USER=", user, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher auth_success_write();
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher auth_args_apply(auth_args + 1, &rset, &home);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (!validate_uid_gid(master_set, rset.uid, rset.gid, user))
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher exit(FATAL_DEFAULT);
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (home != NULL) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (chdir(home) < 0 && errno != ENOENT)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("chdir(%s) failed: %m", home);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (service->set->drop_priv_before_exec) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher disallow_root = service->type == SERVICE_TYPE_AUTH_SERVER ||
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->type == SERVICE_TYPE_AUTH_SOURCE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher restrict_access(&rset, home, disallow_root);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher } else {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher restrict_access_set_env(&rset);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherservice_process_setup_environment(struct service *service, unsigned int uid)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const struct master_service_settings *set;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct service_listener *const *listeners;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char *const *p;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher unsigned int limit, count;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* remove all environment, and put back what we need */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_clean();
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher for (p = service->list->child_process_env; *p != NULL; p++)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(*p);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (service->type) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_CONFIG:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->config_file_path, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_LOG:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* give the log's configuration directly, so it won't depend
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher on config process */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher set = master_service_settings_get(master_service);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put("DOVECONF_ENV=1");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat("LOG_PATH=", set->log_path, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat("INFO_LOG_PATH=", set->info_log_path, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat("LOG_TIMESTAMP=", set->log_timestamp, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat("SYSLOG_FACILITY=", set->syslog_facility, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher default:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher listeners = array_get(&service->list->config->listeners,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher &count);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(count > 0);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher listeners[0]->set.fileset.set->path, NULL));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher limit = service->set->client_limit;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (limit == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* fallback to default limit */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher limit = service->set->master_set->default_client_limit;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u", limit));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(t_strdup_printf(MASTER_UID_ENV"=%u", uid));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (!service->set->master_set->version_ignore)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher env_put(MASTER_DOVECOT_VERSION_ENV"="PACKAGE_VERSION);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void service_process_status_timeout(struct service_process *process)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_error(process->service,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher "Initial status notification not received in %d "
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher "seconds, killing the process",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher SERVICE_FIRST_STATUS_TIMEOUT_SECS);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_error(process->service, "kill(%s, SIGKILL) failed: %m",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dec2str(process->pid));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher timeout_remove(&process->to_status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherhandle_request(const struct service_process_auth_request *request)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher string_t *str;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek if (request == NULL)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (request->data_size > 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str = t_str_new(request->data_size*3);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append(str, "CLIENT_INPUT=");
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher base64_encode(request->data, request->data_size, str);
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher env_put(str_c(str));
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher }
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher env_put(t_strconcat("LOCAL_IP=", net_ip2addr(&request->local_ip), NULL));
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher env_put(t_strconcat("IP=", net_ip2addr(&request->remote_ip), NULL));
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher}
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstruct service_process *
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagherservice_process_create(struct service *service, const char *const *auth_args,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const struct service_process_auth_request *request)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher static unsigned int uid_counter = 0;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct service_process *process;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher unsigned int uid = ++uid_counter;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher int fd[2];
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher pid_t pid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (service->type) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SOURCE:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SERVER:
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
2ca23577d3a25aead24ba759a1f6f67ffc24decfSimo Sorce service_error(service, "socketpair() failed: %m");
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher return NULL;
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher }
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher fd_close_on_exec(fd[0], TRUE);
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher fd_close_on_exec(fd[1], TRUE);
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher break;
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher default:
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher fd[0] = fd[1] = -1;
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher break;
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher }
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher pid = fork();
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek if (pid < 0) {
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek service_error(service, "fork() failed: %m");
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek if (fd[0] != -1) {
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek (void)close(fd[0]);
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek (void)close(fd[1]);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return NULL;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (pid == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* child */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (fd[0] != -1)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (void)close(fd[0]);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_setup_environment(service, uid);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher handle_request(request);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_dup_fds(service, fd[1], request == NULL ? -1 :
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher request->fd, auth_args != NULL);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher drop_privileges(service, auth_args);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process_exec(service->executable, NULL);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (service->type) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SERVER:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process = i_malloc(sizeof(struct service_process_auth_server));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->service = service;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_auth_server_init(process, fd[0]);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (void)close(fd[1]);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SOURCE:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process = i_malloc(sizeof(struct service_process_auth_source));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->service = service;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_auth_source_init(process, fd[0]);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (void)close(fd[1]);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher default:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process = i_new(struct service_process, 1);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->service = service;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(fd[0] == -1);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
681742138b2afbbefa7f14de937beb438409208eSimo Sorce
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->refcount = 1;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->pid = pid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->uid = uid;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->to_status =
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_status_timeout, process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->available_count = service->set->client_limit;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (process->available_count == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* fallback to default limit */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->available_count =
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->set->master_set->default_client_limit;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->process_count++;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->process_avail++;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher hash_table_insert(service->list->pids, &process->pid, process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return process;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallaghervoid service_process_destroy(struct service_process *process)
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct service *service = process->service;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher hash_table_remove(service->list->pids, &process->pid);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (process->available_count > 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->process_avail--;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->process_count--;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(service->process_avail <= service->process_count);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (process->to_status != NULL)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher timeout_remove(&process->to_status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (process->service->type) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SERVER:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_auth_server_deinit(process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case SERVICE_TYPE_AUTH_SOURCE:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_auth_source_deinit(process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher default:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher break;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (service->list->log_byes != NULL)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_notify_add(service->list->log_byes, process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->destroyed = TRUE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_unref(process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallaghervoid service_process_ref(struct service_process *process)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(process->refcount > 0);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->refcount++;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherint service_process_unref(struct service_process *process)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(process->refcount > 0);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (--process->refcount > 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return TRUE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_assert(process->destroyed);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_free(process);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return FALSE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic const char *
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherget_exit_status_message(struct service *service, enum fatal_exit_status status)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher switch (status) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case FATAL_LOGOPEN:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return "Can't open log file";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case FATAL_LOGWRITE:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return "Can't write to log file";
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek case FATAL_LOGERROR:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return "Internal logging error";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case FATAL_OUTOFMEM:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (service->set->vsz_limit == 0)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return "Out of memory";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return t_strdup_printf("Out of memory (vsz_limit=%u MB)",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service->set->vsz_limit);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case FATAL_EXEC:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return "exec() failed";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher case FATAL_DEFAULT:
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return "Fatal failure";
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return NULL;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void log_coredump(struct service *service, string_t *str, int status)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#ifdef WCOREDUMP
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher int signum = WTERMSIG(status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (WCOREDUMP(status)) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append(str, " (core dumped)");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (signum != SIGABRT && signum != SIGSEGV && signum != SIGBUS)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* let's try to figure out why we didn't get a core dump */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (core_dumps_disabled) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_printfa(str, " (core dumps disabled)");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#ifdef HAVE_PR_SET_DUMPABLE
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (!service->set->drop_priv_before_exec) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append(str, " (core not dumped - set drop_priv_before_exec=yes)");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (*service->set->privileged_group != '\0') {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append(str, " (core not dumped - privileged_group prevented it)");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#endif
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_append(str, " (core not dumped)");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#endif
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherservice_process_get_status_error(string_t *str, struct service_process *process,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher int status, bool *default_fatal_r)
d3d297c62e0340151da1d4ce1e082dcfcb45b431Jakub Hrozek{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher struct service *service = process->service;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char *msg;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher *default_fatal_r = FALSE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_printfa(str, "service(%s): child %s ", service->set->name,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dec2str(process->pid));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (WIFSIGNALED(status)) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_printfa(str, "killed with signal %d", WTERMSIG(status));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher log_coredump(service, str, status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (!WIFEXITED(status)) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_printfa(str, "died with status %d", status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
d3d297c62e0340151da1d4ce1e082dcfcb45b431Jakub Hrozek }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher status = WEXITSTATUS(status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (status == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_truncate(str, 0);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_printfa(str, "returned error %d", status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher msg = get_exit_status_message(service, status);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (msg != NULL)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher str_printfa(str, " (%s)", msg);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (status == FATAL_DEFAULT)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher *default_fatal_r = TRUE;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagherstatic void service_process_log(struct service_process *process,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher bool default_fatal, const char *str)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher const char *data;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (!default_fatal || process->service->log_fd[1] == -1) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("%s", str);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* log it via the log process in charge of handling
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher this process's logging */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher data = t_strdup_printf("%d %s DEFAULT-FATAL %s\n",
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher process->service->log_process_internal_fd,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher dec2str(process->pid), str);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (write(process->service->list->master_log_fd[1],
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher data, strlen(data)) < 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("write(log process) failed: %m");
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher i_error("%s", str);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallaghervoid service_process_log_status_error(struct service_process *process,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher int status)
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher{
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher /* fast path */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher return;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher }
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher T_BEGIN {
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher string_t *str = t_str_new(256);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher bool default_fatal;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher service_process_get_status_error(str, process, status,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher &default_fatal);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher if (str_len(str) > 0)
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek service_process_log(process, default_fatal, str_c(str));
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher } T_END;
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher}
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher