mail-user.c revision b06633c63fde22b6c8837ae70b2f95fe60075b0a
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik/* Copyright (c) 2008-2013 Dovecot authors, see the included COPYING file */
b6bc67f3272d8a45fb6b5c01c8a3f8e74010eb71Lukas Slebodnikstruct mail_user_module_register mail_user_module_register = { 0 };
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstruct auth_master_connection *mail_user_auth_master_conn;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic void mail_user_deinit_base(struct mail_user *user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstruct mail_user *mail_user_alloc(const char *username,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik pool = pool_alloconly_create("mail user", 16*1024);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->unexpanded_set = settings_dup(set_info, set, pool);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->set = settings_dup(set_info, set, pool);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->service = master_service_get_name(master_service);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->default_normalizer = uni_utf8_to_decomposed_titlecase;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* check settings so that the duplicated structure will again
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik contain the parsed fields */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (!settings_check(set_info, pool, user->set, &error))
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik i_panic("Settings check unexpectedly failed: %s", error);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik p_array_init(&user->module_contexts, user->pool, 5);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikmail_user_expand_plugins_envs(struct mail_user *user, const char **error_r)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik unsigned int i, count;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (!array_is_created(&user->set->plugin_envs))
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik envs = array_get_modifiable(&user->set->plugin_envs, &count);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "userdb didn't return a home directory, "
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "but plugin setting %s used it (%%h): %s",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik var_expand(str, envs[i+1], mail_user_var_expand_table(user));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik envs[i+1] = p_strdup(user->pool, str_c(str));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikint mail_user_init(struct mail_user *user, const char **error_r)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik const struct mail_storage_settings *mail_set;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik settings_vars_have_key(user->set_info, user->set,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* expand mail_home setting before calling mail_user_get_home() */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik settings_var_expand(user->set_info, user->set,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->pool, mail_user_var_expand_table(user));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (need_home_dir && mail_user_get_home(user, &home) <= 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "userdb didn't return a home directory, "
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (mail_user_expand_plugins_envs(user, error_r) < 0)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_set = mail_user_set_get_storage_set(user);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid mail_user_unref(struct mail_user **_user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* call deinit() with refcount=1, otherwise we may assert-crash in
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_user_ref() that is called by some deinit() handler. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstruct mail_user *mail_user_find(struct mail_user *user, const char *name)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (ns = user->namespaces; ns != NULL; ns = ns->next) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (ns->owner != NULL && strcmp(ns->owner->username, name) == 0)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid mail_user_set_vars(struct mail_user *user, const char *service,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->service = p_strdup(user->pool, service);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (local_ip != NULL && local_ip->family != 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->local_ip = p_new(user->pool, struct ip_addr, 1);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (remote_ip != NULL && remote_ip->family != 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->remote_ip = p_new(user->pool, struct ip_addr, 1);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikmail_user_var_expand_table(struct mail_user *user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik static struct var_expand_table static_tab[] = {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* use a cached table, unless home directory has been set afterwards */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->var_expand_table[4].value == user->_home)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab = p_malloc(user->pool, sizeof(static_tab));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik memcpy(tab, static_tab, sizeof(static_tab));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[1].value = p_strdup(user->pool, t_strcut(user->username, '@'));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[4].value = user->_home; /* don't look it up unless we need it */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[5].value = user->local_ip == NULL ? NULL :
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik p_strdup(user->pool, net_ip2addr(user->local_ip));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[6].value = user->remote_ip == NULL ? NULL :
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik p_strdup(user->pool, net_ip2addr(user->remote_ip));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[8].value = p_strdup(user->pool, dec2str(user->uid));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik tab[9].value = p_strdup(user->pool, dec2str(user->gid));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid mail_user_set_home(struct mail_user *user, const char *home)
e59b73366d3067c576e39a214a34ace2f9a84878Lukas Slebodnikvoid mail_user_add_namespace(struct mail_user *user,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik struct mail_namespace **tmp, *next, *ns = *namespaces;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (strlen(ns->prefix) < strlen((*tmp)->prefix))
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid mail_user_drop_useless_namespaces(struct mail_user *user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* drop all autocreated unusable (typically shared) namespaces.
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik don't drop the autocreated prefix="" namespace that we explicitly
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik created for being the fallback namespace. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (ns = user->namespaces; ns != NULL; ns = next) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if ((ns->flags & NAMESPACE_FLAG_USABLE) == 0 &&
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik (ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0 &&
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikconst char *mail_user_home_expand(struct mail_user *user, const char *path)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik (void)mail_user_try_home_expand(user, &path);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikstatic int mail_user_userdb_lookup_home(struct mail_user *user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik userdb_pool = pool_alloconly_create("userdb lookup", 2048);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik ret = auth_master_user_lookup(mail_user_auth_master_conn,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik auth_user_fields_parse(fields, userdb_pool, &reply);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->_home = p_strdup(user->pool, reply.home);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikint mail_user_get_home(struct mail_user *user, const char **home_r)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* no userdb connection. we can only use mail_home setting. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik } else if ((ret = mail_user_userdb_lookup_home(user)) < 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* userdb lookup failed */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik } else if (ret == 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* user doesn't exist */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik } else if (user->_home == NULL && *user->set->mail_home != '\0') {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* no home returned by userdb lookup, fallback to mail_home
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikbool mail_user_is_plugin_loaded(struct mail_user *user, struct module *module)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik const char *const *plugins;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik plugins = t_strsplit_spaces(user->set->mail_plugins, ", ");
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik ret = str_array_find(plugins, module_get_plugin_name(module));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikconst char *mail_user_plugin_getenv(struct mail_user *user, const char *name)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik return mail_user_set_plugin_getenv(user->set, name);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikconst char *mail_user_set_plugin_getenv(const struct mail_user_settings *set,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik const char *const *envs;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik unsigned int i, count;
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik envs = array_get(&set->plugin_envs, &count);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikint mail_user_try_home_expand(struct mail_user *user, const char **pathp)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* no need to expand home */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikvoid mail_user_set_get_temp_prefix(string_t *dest,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik str_append(dest, master_service_get_name(master_service));
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikconst char *mail_user_get_anvil_userip_ident(struct mail_user *user)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik return t_strconcat(net_ip2addr(user->remote_ip), "/",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikbool mail_user_is_path_mounted(struct mail_user *user, const char *path,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mounts_path = t_strdup_printf("%s/"MOUNTPOINT_LIST_FNAME,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik user->mountpoints = mountpoint_list_init_readonly(mounts_path);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik (void)mountpoint_list_refresh(user->mountpoints);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik rec = mountpoint_list_find(user->mountpoints, path);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (rec == NULL || strcmp(rec->state, MOUNTPOINT_STATE_IGNORE) == 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* we don't have any knowledge of this path's mountpoint.
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik assume it's fine. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* record exists for this mountpoint. see if it's mounted */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (mountpoint_list_update_mounted(user->mountpoints) == 0 &&
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik *error_r = t_strdup_printf("Mountpoint %s isn't mounted. "
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik "Mount it or remove it with doveadm mount remove",
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikmail_user_try_load_class_plugin(struct mail_user *user, const char *name)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mod_set.binary_name = master_service_get_name(master_service);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mod_set.setting_name = "<built-in storage lookup>";
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik module_dir_load_missing(mail_storage_service_modules,
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* initialize the module (and only this module!) immediately so that
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik the class gets registered */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik for (module = mail_storage_service_modules; module != NULL; module = module->next) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (strncmp(module->name, name, name_len) == 0 &&
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik strcmp(module->name + name_len, "_plugin") == 0) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnikmail_user_get_storage_class(struct mail_user *user, const char *name)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (storage == NULL || storage->v.alloc != NULL)
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik /* it's implemented by a plugin. load it and check again. */
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik mail_user_try_load_class_plugin(user, name);
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik if (storage != NULL && storage->v.alloc == NULL) {
49a5412cbc98e630de17359c29cb8d6ce0e16168Lukas Slebodnik i_error("Storage driver '%s' exists as a stub, "