service-process.c revision 55bc6a7a0940ec48a68558ef70838991c5d301d2
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"
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"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service-settings.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "dup2-array.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-log.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-auth-server.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-auth-source.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-process.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <stdlib.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <syslog.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <signal.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <sys/wait.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic const char **
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenservice_dup_fds(struct service *service, int auth_fd, int std_fd)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ARRAY_TYPE(dup2) dups;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, count, n, socket_listener_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);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen t_array_init(&dups, count + 4);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = n = 0; i < count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (listeners[i]->fd == -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, listeners[i]->fd,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MASTER_LISTEN_FD_FIRST + n);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen n++; socket_listener_count++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dup2_append(&dups, null_fd, MASTER_RESERVED_FD);
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 case SERVICE_TYPE_LOG:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services_log_dup2(&dups, service->list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MASTER_LISTEN_FD_FIRST + n,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &socket_listener_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* fall through */
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#ifdef DEBUG
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (socket_listener_count == 1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char **args = t_new(const char *, 3);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen args[0] = "-s";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen args[1] = dec2str(socket_listener_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return args;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int validate_uid_gid(struct master_settings *set, uid_t uid, gid_t gid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *user)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Logins with UID 0 not permitted (user %s)", user);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo 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)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Logins with UID %s (user %s) not permitted "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "(see first_valid_uid in config file)",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dec2str(uid), user);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
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)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Logins for users with primary group ID %s (user %s) "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "not permitted (see first_valid_gid in config file).",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dec2str(gid), user);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void drop_privileges(struct service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *auth_args)
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
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_args_apply(auth_args + 1, &rset, &home);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!validate_uid_gid(master_set, rset.uid, rset.gid, user))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen exit(FATAL_DEFAULT);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (home != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (chdir(home) < 0 && errno != ENOENT)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("chdir(%s) failed: %m", home);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
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{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct master_service_settings *set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *p;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int limit, count;
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 set = master_service_settings_get(master_service);
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));
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 listeners = array_get(&service->list->config->listeners,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(count > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen listeners[0]->set.fileset.set->path, NULL));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen limit = service->set->client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (limit == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* fallback to default limit */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen limit = service->set->master_set->default_client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(t_strdup_printf(MASTER_CLIENT_LIMIT_ENV"=%u", limit));
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);
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct service_process *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenservice_process_create(struct service *service, const char *const *auth_args,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int std_fd, const unsigned char *data, size_t data_size)
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 string_t *str;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd[2];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid_t pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo 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 const char **args;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd[0] != -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)close(fd[0]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_setup_environment(service, uid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (data_size > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str = t_str_new(data_size*3);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, "CLIENT_INPUT=");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen base64_encode(data, data_size, str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen env_put(str_c(str));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen args = service_dup_fds(service, fd[1], std_fd);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen drop_privileges(service, auth_args);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process_exec(service->executable, 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;
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->available_count = service->set->client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process->available_count == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* fallback to default limit */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->available_count =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->set->master_set->default_client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_count++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->process_avail++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_insert(service->list->pids, &process->pid, process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return process;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainenstatic void service_process_log_bye(struct service_process *process)
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen{
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen const char *data;
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen if (process->service->log_fd[1] == -1) {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen /* stopping all services */
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen return;
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen }
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen data = t_strdup_printf("\001%c%s bye\n",
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen LOG_TYPE_OPTION+1, dec2str(process->pid));
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen if (write(process->service->log_fd[1], data, strlen(data)) < 0) {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen if (errno != EAGAIN)
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen i_error("write(log process) failed: %m");
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen else {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen process->io_log_write =
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen io_add(process->service->log_fd[1], IO_WRITE,
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen service_process_log_bye, process);
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen service_process_ref(process);
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen }
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen } else {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen if (process->io_log_write != NULL) {
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen io_remove(&process->io_log_write);
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen service_process_unref(process);
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen }
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen }
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen}
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid service_process_destroy(struct service_process *process)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = process->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_remove(service->list->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);
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;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen service_process_log_bye(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->destroyed = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_unref(process);
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
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen i_assert(process->io_log_write == NULL);
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";
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return t_strdup_printf("Out of memory (vsz_limit=%u MB)",
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void log_coredump(struct service *service, 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,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int status, enum log_type *type_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = process->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *msg;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *type_r = LOG_TYPE_ERROR;
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)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *type_r = LOG_TYPE_ERROR_IGNORE_IF_SEEN_FATAL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_process_log(struct service_process *process,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum log_type type, const char *str)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (type != LOG_TYPE_ERROR_IGNORE_IF_SEEN_FATAL ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process->service->log_fd[1] == -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_log_type(type, "%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 */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen data = t_strdup_printf("\001%c%s %s %s\n",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen type+1, my_pid, dec2str(process->pid), str);
925ef142ae6d9e854cd4e44fbcf2050e744b46beTimo Sirainen if (write(process->service->log_fd[1], data, strlen(data)) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("write(log process) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_log_type(type, "%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);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum log_type type;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_get_status_error(str, process, status, &type);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (str_len(str) > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_log(process, type, str_c(str));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } T_END;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}