mail-user.c revision 88b0427d90f1d3c2c5fb3171e53a505c46e2c39d
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2008-2011 Dovecot authors, see the included COPYING file */
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "lib.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "array.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "hostpid.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "network.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "module-dir.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "home-expand.h"
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi#include "str.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "strescape.h"
c6be98b5270900746f35ebe28bd636019976e29eTimo Sirainen#include "var-expand.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "settings-parser.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "auth-master.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "master-service.h"
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi#include "mail-storage-settings.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "mail-storage-private.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "mail-namespace.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include "mail-storage.h"
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi#include "mail-user.h"
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen#include <stdlib.h>
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenstruct mail_user_module_register mail_user_module_register = { 0 };
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainenstruct auth_master_connection *mail_user_auth_master_conn;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenstatic void mail_user_deinit_base(struct mail_user *user)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen{
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen mail_namespaces_deinit(&user->namespaces);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen}
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenstruct mail_user *mail_user_alloc(const char *username,
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const struct setting_parser_info *set_info,
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const struct mail_user_settings *set)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen{
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen struct mail_user *user;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const char *error;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen pool_t pool;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi i_assert(username != NULL);
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi i_assert(*username != '\0');
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi pool = pool_alloconly_create("mail user", 16*1024);
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi user = p_new(pool, struct mail_user, 1);
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi user->pool = pool;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen user->refcount = 1;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen user->username = p_strdup(pool, username);
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen user->set_info = set_info;
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen user->unexpanded_set = settings_dup(set_info, set, pool);
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen user->set = settings_dup(set_info, set, pool);
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen /* check settings so that the duplicated structure will again
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen contain the parsed fields */
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi if (!settings_check(set_info, pool, user->set, &error))
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi i_panic("Settings check unexpectedly failed: %s", error);
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi user->v.deinit = mail_user_deinit_base;
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi p_array_init(&user->module_contexts, user->pool, 5);
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi return user;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen}
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenstatic int
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenmail_user_expand_plugins_envs(struct mail_user *user, const char **error_r)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen{
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const char **envs, *home;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen string_t *str;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen unsigned int i, count;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (!array_is_created(&user->set->plugin_envs))
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen return 0;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen str = t_str_new(256);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen envs = array_get_modifiable(&user->set->plugin_envs, &count);
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi i_assert((count % 2) == 0);
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen for (i = 0; i < count; i += 2) {
c6be98b5270900746f35ebe28bd636019976e29eTimo Sirainen if (user->_home == NULL &&
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen var_has_key(envs[i+1], 'h', "home") &&
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen mail_user_get_home(user, &home) <= 0) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen *error_r = t_strdup_printf(
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen "userdb didn't return a home directory, "
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen "but plugin setting %s used it (%%h): %s",
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen envs[i], envs[i+1]);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen return -1;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen }
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen str_truncate(str, 0);
c6be98b5270900746f35ebe28bd636019976e29eTimo Sirainen var_expand(str, envs[i+1], mail_user_var_expand_table(user));
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen envs[i+1] = p_strdup(user->pool, str_c(str));
237a6211c7fc4d6dbb58dd0467da6dba1b8f21f6Timo Sirainen }
45ead232666a47819e89dc71dec57767340d0b62Timo Sirainen return 0;
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi}
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenint mail_user_init(struct mail_user *user, const char **error_r)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen{
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const struct mail_storage_settings *mail_set;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen const char *home, *key, *value;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (user->_home == NULL &&
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen settings_vars_have_key(user->set_info, user->set,
2d1892aaeb63b9774237b6e60d6bb04bf6f8259cTimo Sirainen 'h', "home", &key, &value) &&
2d1892aaeb63b9774237b6e60d6bb04bf6f8259cTimo Sirainen mail_user_get_home(user, &home) <= 0) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen *error_r = t_strdup_printf(
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen "userdb didn't return a home directory, "
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen "but %s used it (%%h): %s", key, value);
2d1892aaeb63b9774237b6e60d6bb04bf6f8259cTimo Sirainen return -1;
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen }
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen settings_var_expand(user->set_info, user->set,
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen user->pool, mail_user_var_expand_table(user));
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen if (mail_user_expand_plugins_envs(user, error_r) < 0)
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen return -1;
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen mail_set = mail_user_set_get_storage_set(user);
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen user->mail_debug = mail_set->mail_debug;
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen user->service = master_service_get_name(master_service);
107659c01b2359b0ee426bde020c8d4e29ede30dTimo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen user->initialized = TRUE;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen hook_mail_user_created(user);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen if (user->error != NULL) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen *error_r = t_strdup(user->error);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen return -1;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen }
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen return 0;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen}
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainenvoid mail_user_ref(struct mail_user *user)
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen{
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen i_assert(user->refcount > 0);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen user->refcount++;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen}
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
void mail_user_unref(struct mail_user **_user)
{
struct mail_user *user = *_user;
i_assert(user->refcount > 0);
*_user = NULL;
if (user->refcount > 1) {
user->refcount--;
return;
}
/* call deinit() with refcount=1, otherwise we may assert-crash in
mail_user_ref() that is called by some deinit() handler. */
user->v.deinit(user);
i_assert(user->refcount == 1);
pool_unref(&user->pool);
}
struct mail_user *mail_user_find(struct mail_user *user, const char *name)
{
struct mail_namespace *ns;
for (ns = user->namespaces; ns != NULL; ns = ns->next) {
if (ns->owner != NULL && strcmp(ns->owner->username, name) == 0)
return ns->owner;
}
return NULL;
}
void mail_user_set_vars(struct mail_user *user, uid_t uid, gid_t gid,
const char *service, const struct ip_addr *local_ip,
const struct ip_addr *remote_ip)
{
user->uid = uid;
user->gid = gid;
user->service = p_strdup(user->pool, service);
if (local_ip != NULL && local_ip->family != 0) {
user->local_ip = p_new(user->pool, struct ip_addr, 1);
*user->local_ip = *local_ip;
}
if (remote_ip != NULL && remote_ip->family != 0) {
user->remote_ip = p_new(user->pool, struct ip_addr, 1);
*user->remote_ip = *remote_ip;
}
}
const struct var_expand_table *
mail_user_var_expand_table(struct mail_user *user)
{
static struct var_expand_table static_tab[] = {
{ 'u', NULL, "user" },
{ 'n', NULL, "username" },
{ 'd', NULL, "domain" },
{ 's', NULL, "service" },
{ 'h', NULL, "home" },
{ 'l', NULL, "lip" },
{ 'r', NULL, "rip" },
{ 'p', NULL, "pid" },
{ 'i', NULL, "uid" },
{ '\0', NULL, "gid" },
{ '\0', NULL, NULL }
};
struct var_expand_table *tab;
if (user->var_expand_table != NULL)
return user->var_expand_table;
tab = p_malloc(user->pool, sizeof(static_tab));
memcpy(tab, static_tab, sizeof(static_tab));
tab[0].value = user->username;
tab[1].value = p_strdup(user->pool, t_strcut(user->username, '@'));
tab[2].value = strchr(user->username, '@');
if (tab[2].value != NULL) tab[2].value++;
tab[3].value = user->service;
tab[4].value = user->_home; /* don't look it up unless we need it */
tab[5].value = user->local_ip == NULL ? NULL :
p_strdup(user->pool, net_ip2addr(user->local_ip));
tab[6].value = user->remote_ip == NULL ? NULL :
p_strdup(user->pool, net_ip2addr(user->remote_ip));
tab[7].value = my_pid;
tab[8].value = p_strdup(user->pool, dec2str(user->uid));
tab[9].value = p_strdup(user->pool, dec2str(user->gid));
user->var_expand_table = tab;
return user->var_expand_table;
}
void mail_user_set_home(struct mail_user *user, const char *home)
{
user->_home = p_strdup(user->pool, home);
user->home_looked_up = TRUE;
}
void mail_user_add_namespace(struct mail_user *user,
struct mail_namespace **namespaces)
{
struct mail_namespace **tmp, *next, *ns = *namespaces;
for (; ns != NULL; ns = next) {
next = ns->next;
tmp = &user->namespaces;
for (; *tmp != NULL; tmp = &(*tmp)->next) {
if (strlen(ns->prefix) < strlen((*tmp)->prefix))
break;
}
ns->next = *tmp;
*tmp = ns;
}
*namespaces = user->namespaces;
}
void mail_user_drop_useless_namespaces(struct mail_user *user)
{
struct mail_namespace *ns, *next;
for (ns = user->namespaces; ns != NULL; ns = next) {
next = ns->next;
if ((ns->flags & NAMESPACE_FLAG_USABLE) == 0 &&
(ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0)
mail_namespace_destroy(ns);
}
}
const char *mail_user_home_expand(struct mail_user *user, const char *path)
{
(void)mail_user_try_home_expand(user, &path);
return path;
}
int mail_user_get_home(struct mail_user *user, const char **home_r)
{
struct auth_user_info info;
struct auth_user_reply reply;
pool_t userdb_pool;
const char *username, *const *fields;
int ret;
memset(&info, 0, sizeof(info));
info.service = "lib-storage";
if (user->local_ip != NULL)
info.local_ip = *user->local_ip;
if (user->remote_ip != NULL)
info.remote_ip = *user->remote_ip;
if (user->home_looked_up) {
*home_r = user->_home;
return user->_home != NULL ? 1 : 0;
}
*home_r = NULL;
if (mail_user_auth_master_conn == NULL)
return 0;
userdb_pool = pool_alloconly_create("userdb lookup", 2048);
ret = auth_master_user_lookup(mail_user_auth_master_conn,
user->username, &info, userdb_pool,
&username, &fields);
if (ret >= 0) {
auth_user_fields_parse(fields, userdb_pool, &reply);
user->_home = ret == 0 ? NULL :
p_strdup(user->pool, reply.home);
user->home_looked_up = TRUE;
ret = user->_home != NULL ? 1 : 0;
*home_r = user->_home;
}
pool_unref(&userdb_pool);
return ret;
}
bool mail_user_is_plugin_loaded(struct mail_user *user, struct module *module)
{
const char *const *plugins;
bool ret;
T_BEGIN {
plugins = t_strsplit_spaces(user->set->mail_plugins, ", ");
ret = str_array_find(plugins, module_get_plugin_name(module));
} T_END;
return ret;
}
const char *mail_user_plugin_getenv(struct mail_user *user, const char *name)
{
return mail_user_set_plugin_getenv(user->set, name);
}
const char *mail_user_set_plugin_getenv(const struct mail_user_settings *set,
const char *name)
{
const char *const *envs;
unsigned int i, count;
if (!array_is_created(&set->plugin_envs))
return NULL;
envs = array_get(&set->plugin_envs, &count);
for (i = 0; i < count; i += 2) {
if (strcmp(envs[i], name) == 0)
return envs[i+1];
}
return NULL;
}
int mail_user_try_home_expand(struct mail_user *user, const char **pathp)
{
const char *home, *path = *pathp;
if (mail_user_get_home(user, &home) < 0)
return -1;
path = home_expand_tilde(path, home);
if (path == NULL)
return -1;
*pathp = path;
return 0;
}
void mail_user_set_get_temp_prefix(string_t *dest,
const struct mail_user_settings *set)
{
str_append(dest, set->mail_temp_dir);
str_append(dest, "/dovecot.");
str_append(dest, master_service_get_name(master_service));
str_append_c(dest, '.');
}
const char *mail_user_get_anvil_userip_ident(struct mail_user *user)
{
if (user->remote_ip == NULL)
return NULL;
return t_strconcat(net_ip2addr(user->remote_ip), "/",
str_tabescape(user->username), NULL);
}