mail-storage-service.c revision a48ccadf62d342063d0fff00fadc791423cc915f
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* Copyright (c) 2009-2015 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* If time moves backwards more than this, kill ourself instead of sleeping. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Invalid user settings. Refer to server log for more information."
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct auth_master_connection *conn, *iter_conn;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *set_cache_module, *set_cache_service;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct master_service_settings_cache *set_cache;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *const **userdb_next_fieldsp;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *log_prefix, *auth_token, *auth_user;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *system_groups_user, *uid_source, *gid_source;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct module *mail_storage_service_modules = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmail_user_set_get_mail_debug(const struct setting_parser_info *user_info,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_set = mail_user_set_get_driver_settings(user_info, user_set,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void set_keyval(struct mail_storage_service_ctx *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *str;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (master_service_set_has_config_override(ctx->service, key)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* this setting was already overridden with -o parameter */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mail_user_set_get_mail_debug(user->user_info,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_debug("Ignoring overridden (-o) userdb setting: %s",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (settings_parse_line(set_parser, str) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int set_line(struct mail_storage_service_ctx *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *key, *orig_key, *append_value = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int len;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_debug = mail_user_set_get_mail_debug(user->user_info,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* key+=value */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!settings_parse_is_valid_key(set_parser, key)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* assume it's a plugin setting */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (master_service_set_has_config_override(ctx->service, key)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* this setting was already overridden with -o parameter */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_debug("Ignoring overridden (-o) userdb setting: %s",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen value = settings_parse_get_value(set_parser, key, &type);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "'+' can only be used for strings.", orig_key);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* possibly a password field (e.g. imapc_password).
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen hide the value. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Unknown userdb setting: %s" :
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool validate_chroot(const struct mail_user_settings *user_set,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *dir)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *const *chroot_dirs;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenuser_reply_handle(struct mail_storage_service_ctx *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char **error_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int i, count;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set_keyval(ctx, user, "mail_uid", dec2str(reply->uid));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen set_keyval(ctx, user, "mail_gid", dec2str(reply->gid));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* wu-ftpd like <chroot>/./<home> - check only if there's even
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen a possibility of using them (non-empty valid_chroot_dirs) */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!validate_chroot(user->user_set, chroot)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "userdb returned invalid chroot directory: %s "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str = array_get(&reply->extra_fields, &count);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < count; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "system_groups_user=", 19) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (n != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (strncmp(line, "auth_token=", 11) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen user->auth_token = p_strdup(user->pool, line+11);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (strncmp(line, "auth_user=", 10) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen user->auth_user = p_strdup(user->pool, line+10);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen user->admin = line[6] == 'y' || line[6] == 'Y' ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *error_r = t_strdup_printf("Invalid userdb input '%s': %s",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str[i], settings_parser_get_error(user->set_parser));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenservice_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct mail_storage_service_input *input,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *const **fields_r,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char **error_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen info.service = input->service != NULL ? input->service :
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_debug("changed username to %s", new_username);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (ret == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool parse_uid(const char *str, uid_t *uid_r, const char **error_r)
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen *error_r = t_strdup_printf("getpwnam(%s) failed: %m", str);
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen *error_r = t_strconcat("Unknown UNIX UID user: ", str, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool parse_gid(const char *str, gid_t *gid_r, const char **error_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *error_r = t_strdup_printf("getgrnam(%s) failed: %m", str);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *error_r = t_strconcat("Unknown UNIX GID group: ", str, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic const struct var_expand_table *
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenget_var_expand_table(struct master_service *service,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct mail_storage_service_input *input,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct mail_storage_service_privileges *priv)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen static struct var_expand_table static_tab[] = {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen tab[1].value = t_strcut(input->username, '@');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen tab[5].value = net_ip2addr(&input->remote_ip);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen dec2str(priv->uid == (uid_t)-1 ? geteuid() : priv->uid);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen dec2str(priv->gid == (gid_t)-1 ? getegid() : priv->gid);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (user == NULL || user->auth_user == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen tab[11].value = t_strcut(user->auth_user, '@');
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainenmail_storage_service_get_var_expand_table(struct mail_storage_service_ctx *ctx,
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen return get_var_expand_table(ctx->service, NULL, input, &priv);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic const char *
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenuser_expand_varstr(struct master_service *service,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *str)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen get_var_expand_table(service, user, &user->input, priv));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenservice_parse_privileges(struct mail_storage_service_ctx *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mail_storage_service_privileges *priv_r,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char **error_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct mail_user_settings *set = user->user_set;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!parse_uid(set->mail_uid, &uid, error_r)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *error_r = t_strdup_printf("%s (from %s)", *error_r,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Mail access for users with UID %s not permitted "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "(see first_valid_uid in config file, uid from %s).",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!parse_gid(set->mail_gid, &gid, error_r)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *error_r = t_strdup_printf("%s (from %s)", *error_r,
static void mail_storage_service_seteuid_root(void)
if (seteuid(0) < 0) {
&error)) {
if (disallow_root &&
if (keep_setuid_root) {
if (current_euid != 0) {
if (!setenv_only) {
const char **error_r)
T_BEGIN {
} T_END;
user);
if (diff > 0) {
diff++;
struct mail_storage_service_ctx *
const char *version;
unsigned int count;
geteuid() != 0) {
count = 0;
return ctx;
struct auth_master_connection *
static enum mail_storage_service_flags
return flags;
const char **error_r)
i_unreached();
bool update_log_prefix,
const char **error_r)
void **sets;
geteuid() != 0) {
&error) < 0) {
if (update_log_prefix)
error_r);
if (ret <= 0) {
return ret;
if (ret > 0) {
return ret;
const char **error_r)
bool update_log_prefix;
int ret;
return ret;
const char *error;
unsigned int len;
bool disallow_root =
bool temp_priv_drop =
bool use_chroot;
if (use_chroot) {
if (!temp_priv_drop ||
int ret;
return ret;
const char *error;
const char **error_r)
int ret;
if (ret <= 0)
return ret;
if (ret < 0) {
return ret;
const char *error;
void **sets;
&error) < 0)
int ret = 0;
return ret;
flags);
const char **username_r)
const struct mail_storage_settings *
const struct mail_storage_service_input *
struct setting_parser_context *
T_BEGIN {
} T_END;
return set;