service-process.c revision 617e13833c798435e2be425b99c27ecaad1b8393
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainenservice_dup_fds(struct service *service, int auth_fd, int std_fd)
01f54478a7c69b88ab13840c99bbab19a0d7d754Timo Sirainen unsigned int i, count, n = 0, socket_listener_count, ssl_socket_count;
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* stdin/stdout is already redirected to /dev/null. Other master fds
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen should have been opened with fd_close_on_exec() so we don't have to
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen worry about them.
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen because the destination fd might be another one's source fd we have
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen to be careful not to overwrite anything. dup() the fd when needed */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen listeners = array_get(&service->listeners, &count);
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen services_log_dup2(&dups, service->list, MASTER_LISTEN_FD_FIRST,
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* first add non-ssl listeners */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen for (i = 0; i < count; i++) {
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen (listeners[i]->type != SERVICE_LISTENER_INET ||
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* then ssl-listeners */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen for (i = 0; i < count; i++) {
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen listeners[i]->type == SERVICE_LISTENER_INET &&
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen dup2_append(&dups, null_fd, MASTER_RESERVED_FD);
01f54478a7c69b88ab13840c99bbab19a0d7d754Timo Sirainen dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen env_put(t_strdup_printf("MASTER_AUTH_FD=%d", MASTER_AUTH_FD));
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* set log file to stderr. dup2() here immediately so that
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen we can set up logging to it without causing any log messages
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen to be lost. */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* make sure we don't leak syslog fd. try to do it as late as possible,
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen but also before dup2()s in case syslog fd is one of them. */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen env_put(t_strdup_printf("SSL_SOCKET_COUNT=%d", ssl_socket_count));
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainenstatic int validate_uid_gid(struct master_settings *set, uid_t uid, gid_t gid,
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen i_error("Logins with UID 0 not permitted (user %s)", user);
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) {
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen i_error("Logins with UID %s (user %s) not permitted "
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen "(see first_valid_uid in config file)",
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen (set->last_valid_gid != 0 && gid > (gid_t)set->last_valid_gid)) {
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen i_error("Logins for users with primary group ID %s (user %s) "
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen "not permitted (see first_valid_gid in config file).",
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainenstatic void auth_args_apply(const char *const *args,
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen const char **home)
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen rset->uid = (uid_t)strtoul(*args + 4, NULL, 10);
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen rset->gid = (gid_t)strtoul(*args + 4, NULL, 10);
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen env_put(t_strconcat("HOME=", *args + 5, NULL));
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen else if (strncmp(*args, "system_groups_user=", 19) == 0)
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen else if (strncmp(*args, "mail_access_groups=", 19) == 0) {
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* unknown, set as environment */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* boolean */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* FIXME: kind of ugly to have it
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen env_put(t_strconcat(t_str_ucase(key), value, NULL));
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainenstatic void auth_success_write(void)
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen i_error("creat(%s) failed: %m", AUTH_SUCCESS_PATH);
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainenstatic void drop_privileges(struct service *service,
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen const char *const *auth_args)
77a8c99da71844aaf0fa3036960473024d19f471Timo Sirainen struct master_settings *master_set = service->set->master_set;
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen rset.privileged_gid = service->privileged_gid;
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen rset.chroot_dir = *service->set->chroot == '\0' ? NULL :
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen /* non-authenticating service. don't use *_valid_gid checks */
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen rset.first_valid_gid = master_set->first_valid_gid;
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen rset.last_valid_gid = master_set->last_valid_gid;
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen if (!validate_uid_gid(master_set, rset.uid, rset.gid, user))
c1252a5812eb11fcb81508b9ed37597a5bc84100Timo Sirainen disallow_root = service->type == SERVICE_TYPE_AUTH_SERVER ||
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainenservice_process_setup_environment(struct service *service, unsigned int uid)
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen const char *const *p;
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen /* remove all environment, and put back what we need */
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen for (p = service->list->child_process_env; *p != NULL; p++)
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen /* give the log's configuration directly, so it won't depend
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen on config process */
74ae32512357bdd4872bf160dc697ff7b54b54c5Timo Sirainen set = master_service_settings_get(master_service);
&count);
if (limit == 0) {
struct service_process *
static unsigned int uid_counter = 0;
case SERVICE_TYPE_AUTH_SOURCE:
case SERVICE_TYPE_AUTH_SERVER:
return NULL;
if (pid < 0) {
return NULL;
if (pid == 0) {
if (data_size > 0) {
case SERVICE_TYPE_AUTH_SERVER:
case SERVICE_TYPE_AUTH_SOURCE:
return process;
const char *data;
case SERVICE_TYPE_AUTH_SERVER:
case SERVICE_TYPE_AUTH_SOURCE:
return TRUE;
return FALSE;
switch (status) {
case FATAL_LOGOPEN:
case FATAL_LOGWRITE:
case FATAL_LOGERROR:
case FATAL_OUTOFMEM:
case FATAL_EXEC:
case FATAL_DEFAULT:
return NULL;
#ifdef WCOREDUMP
if (core_dumps_disabled) {
#ifdef HAVE_PR_SET_DUMPABLE
const char *msg;
if (status == 0) {
const char *data;
int status)
T_BEGIN {
bool default_fatal;
} T_END;