mail-storage-service.c revision e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0
/* 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>
/* 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_multi_ctx {
struct master_service *service;
struct auth_master_connection *conn;
struct auth_master_user_list_ctx *auth_list;
unsigned int modules_initialized:1;
};
struct mail_storage_service_multi_user {
struct mail_storage_service_input input;
const char *system_groups_user;
const struct mail_user_settings *user_set;
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 mail_user_settings *user_set,
const struct auth_user_reply *reply,
const char **system_groups_user_r, 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;
}
}
continue;
}
else
/* assume it's a plugin setting */
}
} T_END;
if (ret < 0) {
}
return ret;
}
static int
struct setting_parser_context *set_parser,
const char *service_name,
const struct mail_storage_service_input *input,
const struct mail_user_settings *user_set,
const char **user, const char **system_groups_user_r,
const char **error_r)
{
struct auth_user_info info;
struct auth_user_reply reply;
unsigned int len;
int ret;
if (ret > 0) {
&system_groups_user, error_r) < 0)
ret = -1;
} else {
if (ret == 0)
*error_r = "unknown user";
else
*error_r = "userdb lookup failed";
}
}
pool_unref(&pool);
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, const char *home,
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)
}
/* enable core dumps only when we can be sure that the core
file is written to a safe directory. with chrooting we're
chrooting to user's home dir. */
}
}
static void
const struct mail_storage_service_input *input,
const struct setting_parser_info *set_roots[],
bool preserve_home)
{
const char *error;
unsigned int i;
(void)umask(0077);
}
(void)array_append_space(&all_set_roots);
/* read settings after registering storages so they can have their
own setting definitions too */
}
}
static int
const struct mail_storage_service_input *input,
const char *home,
const struct mail_user_settings *user_set,
bool setuid_root,
struct mail_user **mail_user_r,
const char **error_r)
{
const struct mail_storage_settings *mail_set;
if (mail_set->mail_debug) {
i_info("Effective uid=%s, gid=%s, home=%s",
}
if (setuid_root) {
/* 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' &&
(flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 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_input *input)
{
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 */
}
}
}
static struct mail_user *
const struct mail_storage_service_input *_input,
const struct setting_parser_info *set_roots[],
{
const struct master_service_settings *set;
const struct mail_user_settings *user_set;
const struct mail_storage_settings *mail_set;
struct auth_master_connection *conn;
void **sets;
unsigned int len;
bool userdb_lookup;
if ((flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0)
if (userdb_lookup) {
/* userdb lookup may change settings, do it as soon as
possible. */
&error) <= 0)
/* set up logging again in case username changed */
}
/* variable strings are expanded in mail_user_init(),
but we need the home sooner so do it separately here. */
if (!userdb_lookup) {
}
}
/* If chroot ends with "/.", strip chroot dir from home dir */
}
if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) {
(flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0,
FALSE);
}
/* privileges are now dropped */
return mail_user;
}
struct mail_user *
const struct mail_storage_service_input *_input,
const struct setting_parser_info *set_roots[],
{
T_BEGIN {
} T_END;
return user;
}
void mail_storage_service_deinit_user(void)
{
}
struct mail_storage_service_multi_ctx *
const struct setting_parser_info *set_roots[],
{
struct mail_storage_service_multi_ctx *ctx;
const struct master_service_settings *set;
const struct mail_user_settings *user_set;
const struct mail_storage_settings *mail_set;
void **sets;
/* do all the global initialization. delay initializing plugins until
we drop privileges the first time. */
}
return ctx;
}
struct auth_master_connection *
{
}
const struct mail_storage_service_input *input,
struct mail_storage_service_multi_user **user_r,
const char **error_r)
{
struct mail_storage_service_multi_user *user;
void **sets;
int ret;
error_r);
if (ret <= 0)
return ret;
}
return 1;
}
struct mail_storage_service_multi_user *user,
struct mail_user **mail_user_r,
const char **error_r)
{
const char *home;
unsigned int len;
/* variable strings are expanded in mail_user_init(),
but we need the home sooner so do it separately here. */
TRUE);
}
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 */
} else if (len > 0) {
}
mail_user_r, error_r) < 0)
return -1;
return 0;
}
{
}
unsigned int
{
}
const char **username_r)
{
if (*username_r != NULL)
return 1;
}
{
}
{
}
{
T_BEGIN {
} T_END;
return set;
}