mail-storage-service.c revision 984e5c91288139f8a2582be705ee7ef0d157a3f6
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2009-2013 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* If time moves backwards more than this, kill ourself instead of sleeping. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Invalid user settings. Refer to server log for more information."
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const char *set_cache_module, *set_cache_service;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct master_service_settings_cache *set_cache;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const char *const **userdb_next_fieldsp;
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mail_storage_service_ctx *service_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *system_groups_user, *uid_source, *gid_source;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstruct module *mail_storage_service_modules = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_user_set_get_mail_debug(const struct setting_parser_info *user_info,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_set = mail_user_set_get_driver_settings(user_info, user_set,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void set_keyval(struct mail_storage_service_ctx *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (master_service_set_has_config_override(ctx->service, key)) {
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen /* this setting was already overridden with -o parameter */
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen if (mail_user_set_get_mail_debug(user->user_info,
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen i_debug("Ignoring overridden (-o) userdb setting: %s",
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen if (settings_parse_line(set_parser, str) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int set_line(struct mail_storage_service_ctx *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *key, *orig_key, *append_value = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int len;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen mail_debug = mail_user_set_get_mail_debug(user->user_info,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen /* key+=value */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!settings_parse_is_valid_key(set_parser, key)) {
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen /* assume it's a plugin setting */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (master_service_set_has_config_override(ctx->service, key)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* this setting was already overridden with -o parameter */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("Ignoring overridden (-o) userdb setting: %s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen value = settings_parse_get_value(set_parser, key, &type);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen "'+' can only be used for strings.", orig_key);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* possibly a password field (e.g. imapc_password).
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen hide the value. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Unknown userdb setting: %s" :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool validate_chroot(const struct mail_user_settings *user_set,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *dir)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *chroot_dirs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainenuser_reply_handle(struct mail_storage_service_ctx *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **error_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set_keyval(ctx, user, "mail_uid", dec2str(reply->uid));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set_keyval(ctx, user, "mail_gid", dec2str(reply->gid));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* wu-ftpd like <chroot>/./<home> - check only if there's even
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen a possibility of using them (non-empty valid_chroot_dirs) */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (!validate_chroot(user->user_set, chroot)) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen "userdb returned invalid chroot directory: %s "
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str = array_get(&reply->extra_fields, &count);
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen for (i = 0; i < count; i++) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (strncmp(line, "system_groups_user=", 19) == 0) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (n != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (strncmp(line, "auth_token=", 11) == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->auth_token = p_strdup(user->pool, line+11);
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen *error_r = t_strdup_printf("Invalid userdb input '%s': %s",
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen str[i], settings_parser_get_error(user->set_parser));
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainenservice_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen const struct mail_storage_service_input *input,
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen const char *const **fields_r,
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen const char **error_r)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen info.service = input->service != NULL ? input->service :
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen i_debug("changed username to %s", new_username);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen } else if (ret == 0)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainenstatic bool parse_uid(const char *str, uid_t *uid_r, const char **error_r)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen *error_r = t_strdup_printf("getpwnam(%s) failed: %m", str);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen *error_r = t_strconcat("Unknown UNIX UID user: ", str, NULL);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenstatic bool parse_gid(const char *str, gid_t *gid_r, const char **error_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = t_strdup_printf("getgrnam(%s) failed: %m", str);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = t_strconcat("Unknown UNIX GID group: ", str, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const struct var_expand_table *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenget_var_expand_table(struct master_service *service,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen static struct var_expand_table static_tab[] = {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen tab[1].value = t_strcut(input->username, '@');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab[5].value = net_ip2addr(&input->remote_ip);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab[7].value = dec2str(priv->uid == (uid_t)-1 ? geteuid() : priv->uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab[8].value = dec2str(priv->gid == (gid_t)-1 ? getegid() : priv->gid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_storage_service_get_var_expand_table(struct mail_storage_service_ctx *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return get_var_expand_table(ctx->service, input, &priv);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const char *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenuser_expand_varstr(struct master_service *service,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *str)
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen var_expand(ret, str + 1, get_var_expand_table(service, input, priv));
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipekservice_parse_privileges(struct mail_storage_service_ctx *ctx,
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch struct mail_storage_service_privileges *priv_r,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **error_r)
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen const struct mail_user_settings *set = user->user_set;
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen if (!parse_uid(set->mail_uid, &uid, error_r)) {
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen *error_r = t_strdup_printf("%s (from %s)", *error_r,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen "Mail access for users with UID %s not permitted "
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen "(see first_valid_uid in config file, uid from %s).",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!parse_gid(set->mail_gid, &gid, error_r)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = t_strdup_printf("%s (from %s)", *error_r,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "Mail access for users with GID %s not permitted "
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "(see first_valid_gid in config file, gid from %s).",
&error)) {
if (disallow_root &&
if (keep_setuid_root) {
if (current_euid != 0) {
if (seteuid(0) < 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;
count = 0;
return ctx;
struct auth_master_connection *
static enum mail_storage_service_flags
return flags;
const char **error_r)
i_unreached();
const char **error_r)
void **sets;
geteuid() != 0) {
if (seteuid(0) < 0)
&error) < 0) {
error_r);
if (ret <= 0) {
return ret;
if (ret > 0) {
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 ||
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)
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;