mail-storage-service.c revision 542e28b384a6b26695f3e8de38fd5727d06f3333
/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "hostpid.h"
#include "module-dir.h"
#include "restrict-access.h"
#include "str.h"
#include "var-expand.h"
#include "dict.h"
#include "settings-parser.h"
#include "auth-master.h"
#include "master-service-private.h"
#include "master-service-settings.h"
#include "mail-user.h"
#include "mail-namespace.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#ifdef HAVE_SYS_TIME_H
#endif
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
/* If time moves backwards more than this, kill ourself instead of sleeping. */
#define MAX_TIME_BACKWARDS_SLEEP 5
#define MAX_NOWARN_FORWARD_SECS 10
struct mail_storage_service_ctx {
struct master_service *service;
struct auth_master_connection *conn;
struct auth_master_user_list_ctx *auth_list;
const struct setting_parser_info **set_roots;
unsigned int modules_initialized:1;
unsigned int debug:1;
};
struct mail_storage_service_user {
struct mail_storage_service_input input;
const char *system_groups_user;
const struct mail_user_settings *user_set;
const struct setting_parser_info *user_info;
struct setting_parser_context *set_parser;
};
{
const char *str;
}
}
const char *dir)
{
const char *const *chroot_dirs;
if (*dir == '\0')
return FALSE;
return FALSE;
while (*chroot_dirs != NULL) {
if (**chroot_dirs != '\0' &&
return TRUE;
chroot_dirs++;
}
return FALSE;
}
static int
const struct auth_user_reply *reply,
const char **error_r)
{
unsigned int i, count;
int ret = 0;
*error_r = "userdb returned 0 as uid";
return -1;
}
}
"userdb returned invalid chroot directory: %s "
"(see valid_chroot_dirs setting)",
return -1;
}
}
#ifdef HAVE_SETPRIORITY
if (n != 0) {
if (setpriority(PRIO_PROCESS, 0, n) < 0)
i_error("setpriority(%d) failed: %m", n);
}
#endif
} else T_BEGIN {
else
/* assume it's a plugin setting */
}
} T_END;
}
if (ret < 0) {
}
return ret;
}
static int
const struct mail_storage_service_input *input,
const char *const **fields_r,
const char **error_r)
{
struct auth_user_info info;
const char *new_username;
int ret;
&new_username, fields_r);
if (ret > 0) {
}
*user = new_username;
} else if (ret == 0)
*error_r = "unknown user";
else
*error_r = "userdb lookup failed";
return ret;
}
{
char *p;
if (*p == '\0')
return TRUE;
}
return FALSE;
return TRUE;
}
{
char *p;
if (*p == '\0')
return TRUE;
}
return FALSE;
return TRUE;
}
static void
const char *system_groups_user,
bool disallow_root, bool keep_setuid_root)
{
struct restrict_access_settings rset;
current_euid = geteuid();
(set->last_valid_uid != 0 &&
i_fatal("Mail access for users with UID %s "
"not permitted (see first_valid_uid in config file).",
}
}
(set->last_valid_gid != 0 &&
i_fatal("Mail access for users with GID %s "
"not permitted (see first_valid_gid in config file).",
}
}
}
/* we can't chroot if we want to switch between users. there's not
much point either (from security point of view) */
if (disallow_root &&
i_fatal("Mail access not allowed for root");
if (keep_setuid_root) {
if (current_euid != 0) {
/* we're changing the UID,
switch back to root first */
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
}
}
}
if (setuid_uid != 0) {
if (seteuid(setuid_uid) < 0)
}
}
static int
struct mail_storage_service_user *user,
const char **error_r)
{
const struct mail_storage_settings *mail_set;
if (mail_set->mail_debug) {
i_debug("Effective uid=%s, gid=%s, home=%s",
}
/* we don't want to write core files to any users' home
directories since they could contain information about other
users' mails as well. so do no chdiring to home. */
} else if (*home != '\0' &&
/* If possible chdir to home directory, so that core file
could be written in case we crash. */
else if (mail_set->mail_debug)
}
}
return -1;
}
return -1;
}
*mail_user_r = mail_user;
return 0;
}
static const struct var_expand_table *
struct mail_storage_service_input *input)
{
static struct var_expand_table static_tab[] = {
};
struct var_expand_table *tab;
return tab;
}
static const char *
{
if (*str == SETTING_STRVAR_EXPANDED[0])
return str + 1;
}
static void
struct mail_storage_service_user *user)
{
const struct mail_user_settings *user_set;
void **sets;
T_BEGIN {
} T_END;
}
{
if (diff > 0) {
if (diff > MAX_NOWARN_FORWARD_SECS)
return;
}
if (diff > MAX_TIME_BACKWARDS_SLEEP) {
i_fatal("Time just moved backwards by %ld seconds. "
"This might cause a lot of problems, "
"so I'll just kill myself now. "
} else {
i_error("Time just moved backwards by %ld seconds. "
"I'll sleep now until we're back in present. "
/* Sleep extra second to make sure usecs also grows. */
diff++;
/* don't use sleep()'s return value, because
it could get us to a long loop in case
interrupts just keep coming */
}
}
}
struct mail_storage_service_ctx *
const struct setting_parser_info *set_roots[],
{
struct mail_storage_service_ctx *ctx;
unsigned int count;
(void)umask(0077);
/* @UNSAFE */
count = 0;
else
/* do all the global initialization. delay initializing plugins until
we drop privileges the first time. */
return ctx;
}
struct auth_master_connection *
{
}
static void
{
struct setting_define *new_defs;
struct setting_parser_info *new_info;
unsigned int i, count;
for (i = 0; i < count; i++) {
continue;
}
}
static void
struct master_service_settings_input *input)
{
struct dynamic_settings_parser *new_dyn_parsers;
unsigned int i, count;
/* settings_parser_info_update() modifies the parent structure.
since we may be using the same structure later, we want it to be
in its original state, so we'll have to copy all structures. */
*new_parent = *old_parent;
/* update root */
for (i = 0; i < count; i++) {
new_roots[i] = new_parent;
else
}
/* update parent in dyn_parsers */
for (i = 0; i < count; i++) {
}
}
const struct mail_storage_service_input *input,
const struct setting_parser_info **user_info_r,
const char **error_r)
{
unsigned int i;
/* settings reader may exec doveconf, which is going to clear
environment, and if we're not doing a userdb lookup we want to
use $HOME */
}
error_r) < 0) {
*error_r);
return -1;
}
return 0;
}
}
i_unreached();
return -1;
}
static void
const struct setting_parser_info *user_info,
const struct mail_user_settings *user_set)
{
const struct mail_storage_settings *mail_set;
}
const struct mail_storage_service_input *input,
struct mail_storage_service_user **user_r,
const char **error_r)
{
struct mail_storage_service_user *user;
const struct setting_parser_info *user_info;
const struct mail_user_settings *user_set;
const char *const *userdb_fields;
struct auth_user_reply reply;
void **sets;
int ret = 1;
return -1;
}
error_r);
if (ret <= 0) {
return ret;
}
} else {
}
user->set_parser =
}
if (userdb_fields != NULL) {
ret = -1;
}
return ret;
}
struct mail_storage_service_user *user,
struct mail_user **mail_user_r,
const char **error_r)
{
unsigned int len;
bool temp_priv_drop =
/* variable strings are expanded in mail_user_init(),
but we need the home and chroot sooner so do them separately here. */
i_error("user %s: Relative home directory paths not supported: "
return -1;
}
if (!temp_priv_drop)
}
if (!ctx->modules_initialized) {
/* privileges dropped for the first time. initialize the
modules now to avoid code running as root. */
}
/* we couldn't do chrooting, so if chrooting was enabled fix
the home directory */
/* home dir already contains the chroot dir */
if (!temp_priv_drop) {
if (*home == '\0')
home = "/";
}
} else if (len > 0 && temp_priv_drop) {
}
mail_user_r, error_r) < 0)
return -1;
return 0;
}
const struct mail_storage_service_input *input,
struct mail_storage_service_user **user_r,
struct mail_user **mail_user_r,
const char **error_r)
{
struct mail_storage_service_user *user;
const char *error;
int ret;
if (ret <= 0) {
return ret;
}
return -1;
}
return 1;
}
{
}
unsigned int
{
}
const char **username_r)
{
if (*username_r != NULL)
return 1;
}
{
}
}
{
}
{
T_BEGIN {
} T_END;
return set;
}