service-process.c revision f5e1d3d6b34ec152aa1ff15c7bd3d3552e9227ea
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "common.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "array.h"
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen#include "aqueue.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "istream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ostream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "write-full.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "base64.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hash.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "str.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hostpid.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "env-util.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "fd-close-on-exec.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "restrict-access.h"
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen#include "restrict-process-size.h"
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen#include "eacces-error.h"
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen#include "master-service.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service-settings.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "dup2-array.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service.h"
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen#include "service-anvil.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-log.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-auth-server.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-auth-source.h"
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#include "service-process-notify.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-process.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen#include <grp.h>
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen#include <pwd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <stdlib.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen#include <fcntl.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <syslog.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <signal.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <sys/wait.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen/* Timeout chdir() completely after this many seconds */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen#define CHDIR_TIMEOUT 30
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen/* Give a warning about chdir() taking a while if it took longer than this
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen many seconds to finish. */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen#define CHDIR_WARN_SECS 10
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic void
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenservice_dup_fds(struct service *service, int auth_fd, int std_fd,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen bool give_anvil_fd)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ARRAY_TYPE(dup2) dups;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen unsigned int i, count, n = 0, socket_listener_count, ssl_socket_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
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
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen socket_listener_count = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen listeners = array_get(&service->listeners, &count);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen t_array_init(&dups, count + 10);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen switch (service->type) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen case SERVICE_TYPE_LOG:
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_assert(n == 0);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen services_log_dup2(&dups, service->list, MASTER_LISTEN_FD_FIRST,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen &socket_listener_count);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen n += socket_listener_count;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen break;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen case SERVICE_TYPE_ANVIL:
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* nonblocking anvil fd must be the first one. anvil treats it
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen as the master's fd */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen dup2_append(&dups, service->list->nonblocking_anvil_fd[0],
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen MASTER_LISTEN_FD_FIRST + n++);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen dup2_append(&dups, service->list->blocking_anvil_fd[0],
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen MASTER_LISTEN_FD_FIRST + n++);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen socket_listener_count += 2;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen break;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen default:
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen break;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* first add non-ssl listeners */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen for (i = 0; i < count; i++) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (listeners[i]->fd != -1 &&
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen (listeners[i]->type != SERVICE_LISTENER_INET ||
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen !listeners[i]->set.inetset.set->ssl)) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, listeners[i]->fd,
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen MASTER_LISTEN_FD_FIRST + n);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen n++; socket_listener_count++;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* then ssl-listeners */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen ssl_socket_count = 0;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen for (i = 0; i < count; i++) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (listeners[i]->fd != -1 &&
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen listeners[i]->type == SERVICE_LISTENER_INET &&
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen listeners[i]->set.inetset.set->ssl) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dup2_append(&dups, listeners[i]->fd,
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen MASTER_LISTEN_FD_FIRST + n);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen n++; socket_listener_count++;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen ssl_socket_count++;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (!give_anvil_fd)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen dup2_append(&dups, null_fd, MASTER_ANVIL_FD);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen dup2_append(&dups, service->list->blocking_anvil_fd[1],
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen MASTER_ANVIL_FD);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SOURCE:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SERVER:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(auth_fd != -1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, auth_fd, MASTER_AUTH_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("MASTER_AUTH_FD=%d", MASTER_AUTH_FD));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(auth_fd == -1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, null_fd, MASTER_AUTH_FD);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (std_fd != -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, std_fd, STDIN_FILENO);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, std_fd, STDOUT_FILENO);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put("LOGGED_IN=1");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->type != SERVICE_TYPE_LOG) {
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 i_assert(service->log_fd[1] != -1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put("LOG_SERVICE=1");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("dup2(log fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_internal();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, null_fd, STDERR_FILENO);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
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. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen closelog();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dup2_array(&dups) < 0)
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "dup2s failed");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen env_put(t_strdup_printf("SSL_SOCKET_COUNT=%d", ssl_socket_count));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainenstatic void
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainenvalidate_uid_gid(struct master_settings *set,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen uid_t uid, gid_t gid, const char *user,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen const struct service_process_auth_request *request)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen struct service_process *request_process =
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen request == NULL ? NULL : &request->process->process;
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid == 0) {
d74c7c6d900f7b38017403a0da9106b8a6c647b2Timo Sirainen i_fatal("User %s not allowed to log in using UNIX UID 0 "
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen "(root logins are never allowed)", user);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen if (request != NULL && request_process->service->uid == uid &&
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen master_uid != uid) {
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen struct passwd *pw;
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen pw = getpwuid(uid);
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen i_fatal("User %s not allowed to log in using %s's "
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen "UNIX UID %s%s (see http://wiki.dovecot.org/UserIds)",
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen user, request_process->service->set->name,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen dec2str(uid), pw == NULL ? "" :
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen t_strdup_printf("(%s)", pw->pw_name));
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen }
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid < (uid_t)set->first_valid_uid ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) {
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen struct passwd *pw;
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen bool low = uid < (uid_t)set->first_valid_uid;
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen pw = getpwuid(uid);
d74c7c6d900f7b38017403a0da9106b8a6c647b2Timo Sirainen i_fatal("User %s not allowed to log in using too %s "
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen "UNIX UID %s%s (see %s in config file)",
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen user, low ? "low" : "high",
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen dec2str(uid), pw == NULL ? "" :
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen t_strdup_printf("(%s)", pw->pw_name),
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen low ? "first_valid_uid" : "last_valid_uid");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (gid < (gid_t)set->first_valid_gid ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (set->last_valid_gid != 0 && gid > (gid_t)set->last_valid_gid)) {
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen struct group *gr;
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen bool low = gid < (gid_t)set->first_valid_gid;
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen gr = getgrgid(gid);
d74c7c6d900f7b38017403a0da9106b8a6c647b2Timo Sirainen i_fatal("User %s not allowed to log in using too %s primary "
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen "UNIX group ID %s%s (see %s in config file)",
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen user, low ? "low" : "high",
5323bec1c24184863a13bc14a2dc9487093eea3dTimo Sirainen dec2str(gid), gr == NULL ? "" :
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen t_strdup_printf("(%s)", gr->gr_name),
0ef40aa9ca6084393fe0a56feac2cf801e8b52f0Timo Sirainen low ? "first_valid_gid" : "last_valid_gid");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void auth_args_apply(const char *const *args,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct restrict_access_settings *rset,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char **home)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen const char *key, *value;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen string_t *expanded_vars;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen expanded_vars = t_str_new(128);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen str_append(expanded_vars, "VARS_EXPANDED=");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (; *args != NULL; args++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strncmp(*args, "uid=", 4) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->uid = (uid_t)strtoul(*args + 4, NULL, 10);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (strncmp(*args, "gid=", 4) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->gid = (gid_t)strtoul(*args + 4, NULL, 10);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (strncmp(*args, "home=", 5) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *home = *args + 5;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("HOME=", *args + 5, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (strncmp(*args, "chroot=", 7) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->chroot_dir = *args + 7;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (strncmp(*args, "system_groups_user=", 19) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->system_groups_user = *args + 19;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (strncmp(*args, "mail_access_groups=", 19) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->extra_groups =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->extra_groups == NULL ? *args + 19 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen t_strconcat(*args + 19, ",",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset->extra_groups, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* unknown, set as environment */
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen value = strchr(*args, '=');
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen if (value == NULL) {
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen /* boolean */
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen key = *args;
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen value = "=1";
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen } else {
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen key = t_strdup_until(*args, value);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen if (strcmp(key, "mail") == 0) {
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen /* FIXME: kind of ugly to have it
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen here.. */
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen key = "mail_location";
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen }
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen }
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen str_append(expanded_vars, key);
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen str_append_c(expanded_vars, ' ');
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen env_put(t_strconcat(t_str_ucase(key), value, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen env_put(str_c(expanded_vars));
e3ae2ac7a93b418cf46e829c94973b6e962a7830Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainenstatic void auth_success_write(void)
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen{
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen int fd;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen if (auth_success_written)
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen return;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen fd = creat(AUTH_SUCCESS_PATH, 0666);
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen if (fd == -1)
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen i_error("creat(%s) failed: %m", AUTH_SUCCESS_PATH);
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen else
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen (void)close(fd);
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen auth_success_written = TRUE;
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen}
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainenstatic void chdir_to_home(const struct restrict_access_settings *rset,
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen const char *user, const char *home)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen{
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen unsigned int left;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen int ret, chdir_errno;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (*home != '/') {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("user %s: Relative home directory paths not supported: "
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen "%s", user, home);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* if home directory is NFS-mounted, we might not have access to it as
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen root. Change the effective UID and GID temporarily to make it
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen work. */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (rset->uid != master_uid) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (setegid(rset->gid) < 0)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("setegid(%s) failed: %m", dec2str(rset->gid));
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (seteuid(rset->uid) < 0)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("seteuid(%s) failed: %m", dec2str(rset->uid));
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen alarm(CHDIR_TIMEOUT);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ret = chdir(home);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen chdir_errno = errno;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if ((left = alarm(0)) < CHDIR_TIMEOUT - CHDIR_WARN_SECS) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_warning("user %s: chdir(%s) blocked for %u secs",
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen user, home, CHDIR_TIMEOUT - left);
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen errno = chdir_errno;
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (ret == 0) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* chdir succeeded */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen } else if ((errno == ENOENT || errno == ENOTDIR || errno == EINTR) &&
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen rset->chroot_dir == NULL) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* Not chrooted, fallback to using /tmp.
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ENOENT: No home directory yet, but it might be automatically
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen created by the service process, so don't complain.
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen ENOTDIR: This check is mainly for /dev/null home directory.
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen EINTR: chdir() timed out. */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen } else if (errno == EACCES) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("user %s: %s", user, eacces_error_get("chdir", home));
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen } else {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("user %s: chdir(%s) failed with uid %s: %m",
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen user, home, dec2str(rset->uid));
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* Change UID back. No need to change GID back, it doesn't
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen really matter. */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (rset->uid != master_uid && seteuid(master_uid) < 0)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("seteuid(%s) failed: %m", dec2str(master_uid));
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (ret < 0) {
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen /* We still have to change to some directory where we have
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen rx-access. /tmp should exist everywhere. */
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (chdir("/tmp") < 0)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen i_fatal("chdir(/tmp) failed: %m");
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen }
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen}
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainenstatic void
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainendrop_privileges(struct service *service, const char *const *auth_args,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen const struct service_process_auth_request *request)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_settings *master_set = service->set->master_set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct restrict_access_settings rset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *user, *home = NULL;
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen bool disallow_root;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
e154d8764089896a693cbb83d6831b2398f22ee8Timo Sirainen if (auth_args != NULL && service->set->master_set->mail_debug)
e154d8764089896a693cbb83d6831b2398f22ee8Timo Sirainen env_put("DEBUG=1");
e154d8764089896a693cbb83d6831b2398f22ee8Timo Sirainen
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen if (service->set->vsz_limit != 0)
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen restrict_process_size(service->set->vsz_limit, -1U);
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen restrict_access_init(&rset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.uid = service->uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.gid = service->gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.privileged_gid = service->privileged_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->set->chroot;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.extra_groups = service->extra_gids;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (auth_args == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* non-authenticating service. don't use *_valid_gid checks */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(auth_args[0] != NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.first_valid_gid = master_set->first_valid_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rset.last_valid_gid = master_set->last_valid_gid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen user = auth_args[0];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat("USER=", user, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen auth_success_write();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_args_apply(auth_args + 1, &rset, &home);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen validate_uid_gid(master_set, rset.uid, rset.gid, user,
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen request);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen if (home != NULL)
c60178b2610a9b193ff72aa18448398ef72529a1Timo Sirainen chdir_to_home(&rset, user, home);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen if (service->set->drop_priv_before_exec) {
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen disallow_root = service->type == SERVICE_TYPE_AUTH_SERVER ||
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen service->type == SERVICE_TYPE_AUTH_SOURCE;
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen restrict_access(&rset, home, disallow_root);
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen restrict_access_set_env(&rset);
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenservice_process_setup_environment(struct service *service, unsigned int uid)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen const struct master_service_settings *set = service->list->service_set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *p;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* remove all environment, and put back what we need */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_clean();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (p = service->list->child_process_env; *p != NULL; p++)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(*p);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_CONFIG:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->config_file_path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_LOG:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* give the log's configuration directly, so it won't depend
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen on config process */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put("DOVECONF_ENV=1");
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 break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen services_get_config_socket_path(service->list), NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u",
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen service->client_limit));
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen if (service->set->service_count != 0) {
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen env_put(t_strdup_printf(MASTER_SERVICE_COUNT_ENV"=%u",
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen service->set->service_count));
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_UID_ENV"=%u", uid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->master_set->version_ignore)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(MASTER_DOVECOT_VERSION_ENV"="PACKAGE_VERSION);
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen if (*ssl_manual_key_password != '\0' && 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"=",
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen ssl_manual_key_password, NULL));
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_status_timeout(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(process->service,
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen "Initial status notification not received in %d "
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen "seconds, killing the process",
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen SERVICE_FIRST_STATUS_TIMEOUT_SECS);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(process->service, "kill(%s, SIGKILL) failed: %m",
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen dec2str(process->pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&process->to_status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenstatic void
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenhandle_request(const struct service_process_auth_request *request)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen string_t *str;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (request == NULL)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (request->data_size > 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen str = t_str_new(request->data_size*3);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen str_append(str, "CLIENT_INPUT=");
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen base64_encode(request->data, request->data_size, str);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen env_put(str_c(str));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen env_put(t_strconcat("LOCAL_IP=", net_ip2addr(&request->local_ip), NULL));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen env_put(t_strconcat("IP=", net_ip2addr(&request->remote_ip), NULL));
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainenstatic const char **
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainenget_extra_args(struct service *service,
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen const struct service_process_auth_request *request,
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen const char *const *auth_args)
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen{
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen const char **extra;
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen if (!service->set->master_set->verbose_proctitle || request == NULL)
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen return NULL;
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen extra = t_new(const char *, 2);
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen extra[0] = t_strdup_printf("[%s %s]", auth_args[0],
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen net_ip2addr(&request->remote_ip));
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen return extra;
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen}
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct service_process *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenservice_process_create(struct service *service, const char *const *auth_args,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen const struct service_process_auth_request *request)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen static unsigned int uid_counter = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_process *process;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int uid = ++uid_counter;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd[2];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid_t pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (service->to_throttle != NULL) {
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen /* throttling service, don't create new processes */
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen return NULL;
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen }
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen if (service->process_count >= service->process_limit) {
e4427a13680e8b7db98fb7eb9ef2e5f788e84212Timo Sirainen /* we should get here only with auth dest services */
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen i_warning("service(%s): process_limit reached, "
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen "dropping this client connection",
e4427a13680e8b7db98fb7eb9ef2e5f788e84212Timo Sirainen service->set->name);
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen return NULL;
e20edc0dedcdfbcfa20e9bb4c3dc460f28bfd405Timo Sirainen }
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SOURCE:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SERVER:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "socketpair() failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd_close_on_exec(fd[0], TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd_close_on_exec(fd[1], TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd[0] = fd[1] = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid = fork();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (pid < 0) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "fork() failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd[0] != -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)close(fd[0]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)close(fd[1]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (pid == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* child */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd[0] != -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)close(fd[0]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_setup_environment(service, uid);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen handle_request(request);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service_dup_fds(service, fd[1], request == NULL ? -1 :
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen request->fd, auth_args != NULL);
fb7ac3e31c92627efe076318319976ac1c27ae2aTimo Sirainen drop_privileges(service, auth_args, request);
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen process_exec(service->executable,
ce78f5edeb05611677a50034e5e8ddc4c72d446aTimo Sirainen get_extra_args(service, request, auth_args));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SERVER:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process = i_malloc(sizeof(struct service_process_auth_server));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->service = service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_auth_server_init(process, fd[0]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)close(fd[1]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SOURCE:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process = i_malloc(sizeof(struct service_process_auth_source));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->service = service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_auth_source_init(process, fd[0]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)close(fd[1]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen case SERVICE_TYPE_ANVIL:
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen service_anvil_process_created(service);
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen /* fall through */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process = i_new(struct service_process, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->service = service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(fd[0] == -1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->refcount = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->pid = pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->uid = uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->to_status =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_status_timeout, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen process->available_count = service->client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_count++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_avail++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen service_list_ref(service->list);
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen hash_table_insert(service_pids, &process->pid, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return process;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_destroy(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = process->service;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen struct service_list *service_list = service->list;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen hash_table_remove(service_pids, &process->pid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process->available_count > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_avail--;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_count--;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->process_avail <= service->process_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process->to_status != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&process->to_status);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (process->to_idle != NULL)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen timeout_remove(&process->to_idle);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (process->service->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SERVER:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_auth_server_deinit(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_TYPE_AUTH_SOURCE:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_auth_source_deinit(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen case SERVICE_TYPE_ANVIL:
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen service_anvil_process_destroyed(service);
cf2e6953d03a1c22f272ec19432fc03c136ac1bbTimo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (service->list->log_byes != NULL)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service_process_notify_add(service->list->log_byes, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->destroyed = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_unref(process);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->process_count < service->process_limit &&
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service->type == SERVICE_TYPE_AUTH_SOURCE)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service_processes_auth_source_notify(service, FALSE);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen service_list_unref(service_list);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_ref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(process->refcount > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->refcount++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint service_process_unref(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(process->refcount > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (--process->refcount > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(process->destroyed);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_free(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenget_exit_status_message(struct service *service, enum fatal_exit_status status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (status) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_LOGOPEN:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Can't open log file";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_LOGWRITE:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Can't write to log file";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_LOGERROR:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Internal logging error";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_OUTOFMEM:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->set->vsz_limit == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Out of memory";
a3dcda4b01461c7690c655a013ec12851cdb78d4Timo Sirainen return t_strdup_printf("Out of memory (vsz_limit=%u MB, "
a3dcda4b01461c7690c655a013ec12851cdb78d4Timo Sirainen "you may need to increase it)",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->set->vsz_limit);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_EXEC:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "exec() failed";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case FATAL_DEFAULT:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "Fatal failure";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5fc02738b38ac2b0c21db0854d7a5ad452b1177fTimo Sirainenstatic void log_coredump(struct service *service ATTR_UNUSED,
5fc02738b38ac2b0c21db0854d7a5ad452b1177fTimo Sirainen string_t *str, int status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#ifdef WCOREDUMP
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int signum = WTERMSIG(status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (WCOREDUMP(status)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " (core dumped)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (signum != SIGABRT && signum != SIGSEGV && signum != SIGBUS)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* let's try to figure out why we didn't get a core dump */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (core_dumps_disabled) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (core dumps disabled)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#ifdef HAVE_PR_SET_DUMPABLE
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!service->set->drop_priv_before_exec) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " (core not dumped - set drop_priv_before_exec=yes)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*service->set->privileged_group != '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " (core not dumped - privileged_group prevented it)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, " (core not dumped)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenservice_process_get_status_error(string_t *str, struct service_process *process,
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen int status, bool *default_fatal_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = process->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *msg;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen *default_fatal_r = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen str_printfa(str, "service(%s): child %s ", service->set->name,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dec2str(process->pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (WIFSIGNALED(status)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, "killed with signal %d", WTERMSIG(status));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen log_coredump(service, str, status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!WIFEXITED(status)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, "died with status %d", status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen status = WEXITSTATUS(status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (status == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_truncate(str, 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, "returned error %d", status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen msg = get_exit_status_message(service, status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (msg != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_printfa(str, " (%s)", msg);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (status == FATAL_DEFAULT)
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen *default_fatal_r = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_log(struct service_process *process,
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen bool default_fatal, const char *str)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen if (!default_fatal || process->service->log_fd[1] == -1) {
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen i_error("%s", str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* log it via the log process in charge of handling
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen this process's logging */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen data = t_strdup_printf("%d %s DEFAULT-FATAL %s\n",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen process->service->log_process_internal_fd,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen dec2str(process->pid), str);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (write(process->service->list->master_log_fd[1],
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen data, strlen(data)) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("write(log process) failed: %m");
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen i_error("%s", str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_log_status_error(struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* fast path */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen T_BEGIN {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen string_t *str = t_str_new(256);
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen bool default_fatal;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen service_process_get_status_error(str, process, status,
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen &default_fatal);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (str_len(str) > 0)
9c8f854d95d8d895022a75f140a0a500eb200d39Timo Sirainen service_process_log(process, default_fatal, str_c(str));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } T_END;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}