mail-storage-service.c revision b34fdb68d376d85b4880da4a4bdf67ae726a381b
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenmaster_service_set(struct master_service *service,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const char *str;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (settings_parse_line(service->set_parser, str) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen settings_parser_get_error(service->set_parser));
9514dbd41faad453406fc3a10aca791417a9ce75Timo Sirainenstatic bool validate_chroot(const struct mail_user_settings *user_set,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *dir)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const char *const *chroot_dirs;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenuser_reply_handle(struct master_service *service,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const char **system_groups_user_r, const char **error_r)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen unsigned int i, count;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen master_service_set(service, "mail_uid", dec2str(reply->uid));
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen master_service_set(service, "mail_gid", dec2str(reply->gid));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen master_service_set(service, "mail_home", reply->home);
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen if (!validate_chroot(user_set, reply->chroot)) {
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen "userdb returned invalid chroot directory: %s "
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen "(see valid_chroot_dirs setting)",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen master_service_set(service, "mail_chroot", reply->chroot);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen str = array_get(&reply->extra_fields, &count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (i = 0; i < count && ret == 0; i++) T_BEGIN {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strncmp(line, "system_groups_user=", 19) == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen line = t_strconcat("mail_location=", line + 5, NULL);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (!settings_parse_is_valid_key(service->set_parser, key)) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* assume it's a plugin setting */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen ret = settings_parse_line(service->set_parser, line);
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen *error_r = t_strdup_printf("Invalid userdb input '%s': %s",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str[i], settings_parser_get_error(service->set_parser));
ce3faaaaab3e2d45b023396287e02f88e5c76e74Timo Sirainenservice_auth_userdb_lookup(struct master_service *service, bool debug,
ce3faaaaab3e2d45b023396287e02f88e5c76e74Timo Sirainen const char **user, const char **system_groups_user_r,
ce3faaaaab3e2d45b023396287e02f88e5c76e74Timo Sirainen const char **error_r)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *system_groups_user, *orig_user = *user;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen unsigned int len;
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen pool = pool_alloconly_create("userdb lookup", 1024);
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen conn = auth_master_init(user_set->auth_socket_path, debug);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = auth_master_user_lookup(conn, *user, service->name,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen len = reply.chroot == NULL ? 0 : strlen(reply.chroot);
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen if (user_reply_handle(service, user_set, &reply,
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen *system_groups_user_r = t_strdup(system_groups_user);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (ret > 0 && strcmp(*user, orig_user) != 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (mail_user_set_get_storage_set(user_set)->mail_debug)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ", service->name,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic bool parse_uid(const char *str, uid_t *uid_r)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (*p == '\0')
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic bool parse_gid(const char *str, gid_t *gid_r)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (*p == '\0')
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainenservice_drop_privileges(const struct mail_user_settings *set,
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen const char *system_groups_user, const char *home,
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen i_fatal("Unknown mail_uid user: %s", set->mail_uid);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "not permitted (see first_valid_uid in config file).",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_fatal("Unknown mail_gid group: %s", set->mail_gid);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "not permitted (see first_valid_gid in config file).",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (!parse_uid(set->mail_privileged_group, &rset.privileged_gid))
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen i_fatal("Unknown mail_gid group: %s", set->mail_gid);
56963ffad65b860c827553dfaf09fb766cb7e20eTimo Sirainen /* we can't chroot if we want to switch between users. there's not
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen much point either (from security point of view) */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen rset.chroot_dir = *set->mail_chroot == '\0' || keep_setuid_root ?
56963ffad65b860c827553dfaf09fb766cb7e20eTimo Sirainen (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0)))
56963ffad65b860c827553dfaf09fb766cb7e20eTimo Sirainen if (keep_setuid_root && current_euid != rset.uid) {
56963ffad65b860c827553dfaf09fb766cb7e20eTimo Sirainen /* we're changing the UID, switch back to root first */
56963ffad65b860c827553dfaf09fb766cb7e20eTimo Sirainen restrict_access(&rset, *home == '\0' ? NULL : home, disallow_root);
56963ffad65b860c827553dfaf09fb766cb7e20eTimo Sirainen i_fatal("seteuid(%s) failed: %m", dec2str(setuid_uid));
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenmail_storage_service_init_settings(struct master_service *service,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const struct setting_parser_info *set_roots[3];
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen set_roots[0] = &mail_user_setting_parser_info;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* read settings after registering storages so they can have their
a1607f6001a9949e1cf9d49eb0aa936dbb4c77ffTimo Sirainen own setting definitions too */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (master_service_settings_read(service, set_roots,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_fatal("Error reading configuration: %s", error);
a1607f6001a9949e1cf9d49eb0aa936dbb4c77ffTimo Sirainenmail_storage_service_init_post(struct master_service *service,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char **error_r)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen mail_set = mail_user_set_get_storage_set(user_set);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* If possible chdir to home directory, so that core file
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen could be written in case we crash. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen mail_user_set_vars(mail_user, geteuid(), service->name, NULL, NULL);
9514dbd41faad453406fc3a10aca791417a9ce75Timo Sirainen mail_namespaces_init(mail_user, error_r) < 0) {
static const struct var_expand_table *
return tab;
const char *str)
struct mail_user *
void **sets;
unsigned int len;
bool userdb_lookup;
if (userdb_lookup) {
&error) <= 0)
if (!userdb_lookup) {
return mail_user;
void mail_storage_service_deinit_user(void)
struct mail_storage_service_multi_ctx *
void **sets;
return ctx;
const char *user,
const char **error_r)
void **sets;
unsigned int len;
int ret;
error_r);
if (ret <= 0)
return ret;
} else if (len > 0) {
void **sets;