mail-storage-service.c revision 674f541b16689c0ed090dac32db94463c5af3977
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen/* If time moves backwards more than this, kill ourself instead of sleeping. */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen const char *set_cache_module, *set_cache_service;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen struct master_service_settings_cache *set_cache;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const struct dynamic_settings_parser *set_cache_dyn_parsers;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct setting_parser_info *set_cache_dyn_parsers_parent;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const struct setting_parser_info **set_cache_roots;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainenstatic void set_keyval(struct setting_parser_context *set_parser,
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen const char *str;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (settings_parse_line(set_parser, str) < 0) {
8da095519878426b012058e6f331a669f327f47fTimo Sirainenstatic bool validate_chroot(const struct mail_user_settings *user_set,
8da095519878426b012058e6f331a669f327f47fTimo Sirainen const char *dir)
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen const char *const *chroot_dirs;
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenuser_reply_handle(struct mail_storage_service_user *user,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen const char **error_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct setting_parser_context *set_parser = user->set_parser;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen unsigned int i, count;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen set_keyval(set_parser, "mail_uid", dec2str(reply->uid));
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen set_keyval(set_parser, "mail_gid", dec2str(reply->gid));
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen set_keyval(set_parser, "mail_home", reply->home);
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen if (!validate_chroot(user->user_set, reply->chroot)) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "userdb returned invalid chroot directory: %s "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "(see valid_chroot_dirs setting)",
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen set_keyval(set_parser, "mail_chroot", reply->chroot);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen str = array_get(&reply->extra_fields, &count);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (strncmp(line, "system_groups_user=", 19) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (n != 0) {
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen if (!settings_parse_is_valid_key(set_parser, key)) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* assume it's a plugin setting */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *error_r = t_strdup_printf("Invalid userdb input '%s': %s",
bd2e2500e64c00349ee00e28797809b4029db52fTimo Sirainen str[i], settings_parser_get_error(set_parser));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenservice_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen const struct mail_storage_service_input *input,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen const char *const **fields_r,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char **error_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_debug("changed username to %s", new_username);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (ret == 0)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainenstatic bool parse_uid(const char *str, uid_t *uid_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (*p == '\0')
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic bool parse_gid(const char *str, gid_t *gid_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (*p == '\0')
3bc2b84acd8c5731a0bc9d69fbcd3103b68e9b52Timo Sirainenservice_drop_privileges(const struct mail_user_settings *set,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen i_fatal("Unknown mail_uid user: %s", set->mail_uid);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "not permitted (see first_valid_uid in config file).",
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_fatal("Unknown mail_gid group: %s", set->mail_gid);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "not permitted (see first_valid_gid in config file).",
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid)) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* we can't chroot if we want to switch between users. there's not
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen much point either (from security point of view) */
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen rset.chroot_dir = *chroot == '\0' || keep_setuid_root ? NULL : chroot;
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0)))
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen /* we're changing the UID,
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen switch back to root first */
47001341950b8588c5f3a96b75864dab48e279aeTimo Sirainen restrict_access(&rset, *home == '\0' ? NULL : home,
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen i_fatal("seteuid(%s) failed: %m", dec2str(setuid_uid));
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainenmail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen const char *home, struct mail_user **mail_user_r,
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen const char **error_r)
728a9c39b63b48f17600e6a1e5ebfc93d0896a24Timo Sirainen mail_user = mail_user_alloc(user->input.username, user->user_info,
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
728a9c39b63b48f17600e6a1e5ebfc93d0896a24Timo Sirainen mail_user_set_vars(mail_user, geteuid(), ctx->service->name,
728a9c39b63b48f17600e6a1e5ebfc93d0896a24Timo Sirainen &user->input.local_ip, &user->input.remote_ip);
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen mail_set = mail_user_set_get_storage_set(mail_user);
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen dec2str(geteuid()), dec2str(getegid()), home);
e34d4597fc4995a067caafdc27676f6cebb0aa28Timo Sirainen if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* we don't want to write core files to any users' home
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen directories since they could contain information about other
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen users' mails as well. so do no chdiring to home. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* If possible chdir to home directory, so that core file
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen could be written in case we crash. */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (mail_namespaces_init(mail_user, error_r) < 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic const struct var_expand_table *
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainenget_var_expand_table(struct master_service *service,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen static struct var_expand_table static_tab[] = {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen tab[1].value = t_strcut(input->username, '@');
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen tab[5].value = net_ip2addr(&input->remote_ip);
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainenstatic const char *
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainenuser_expand_varstr(struct master_service *service,
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen struct mail_storage_service_input *input, const char *str)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen var_expand(ret, str + 1, get_var_expand_table(service, input));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenmail_storage_service_init_log(struct master_service *service,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen user_set = master_service_settings_get_others(service)[0];
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen var_expand(str, user->user_set->mail_log_prefix,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void mail_storage_service_time_moved(time_t old_time, time_t new_time)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_warning("Time jumped forwards %ld seconds", diff);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_fatal("Time just moved backwards by %ld seconds. "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "This might cause a lot of problems, "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "so I'll just kill myself now. "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "http://wiki.dovecot.org/TimeMovedBackwards", diff);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_error("Time just moved backwards by %ld seconds. "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "I'll sleep now until we're back in present. "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "http://wiki.dovecot.org/TimeMovedBackwards", diff);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* Sleep extra second to make sure usecs also grows. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* don't use sleep()'s return value, because
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen it could get us to a long loop in case
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen interrupts just keep coming */
struct mail_storage_service_ctx *
unsigned int count;
count = 0;
return ctx;
struct auth_master_connection *
unsigned int i, count;
for (i = 0; i < count; i++) {
static struct setting_parser_info *
unsigned int i, count;
for (i = 0; i < count; i++) {
for (i = 0; i < count; i++) {
return new_parent;
const char **error_r)
i_unreached();
const char **error_r)
const char *const *userdb_fields;
error_r) < 0) {
error_r);
if (ret <= 0) {
return ret;
i_unreached();
return ret;
const char **error_r)
unsigned int len;
bool temp_priv_drop =
if (!temp_priv_drop ||
if (!temp_priv_drop) {
const char **error_r)
const char *error;
int ret;
if (ret <= 0) {
return ret;
const char *error;
&error) < 0)
const char **username_r)
const struct mail_storage_service_input *
struct setting_parser_context *
T_BEGIN {
} T_END;
return set;