mail-storage-service.c revision d6601a0bc4fd60e58bedbddf2481abd82cba76d7
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2009-2015 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "base64.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "hostpid.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "module-dir.h"
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen#include "restrict-access.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "eacces-error.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "ipwd.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "str.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "var-expand.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "dict.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "settings-parser.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "auth-master.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "master-service-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "master-service-settings.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "master-service-settings-cache.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-user.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-namespace.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-storage.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-storage-service.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <sys/stat.h>
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen#ifdef HAVE_SYS_TIME_H
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen# include <sys/time.h>
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen#endif
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen#ifdef HAVE_SYS_RESOURCE_H
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen# include <sys/resource.h>
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen#endif
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen/* If time moves backwards more than this, kill ourself instead of sleeping. */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#define MAX_TIME_BACKWARDS_SLEEP 5
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#define MAX_NOWARN_FORWARD_SECS 10
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define ERRSTR_INVALID_USER_SETTINGS \
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen "Invalid user settings. Refer to server log for more information."
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct mail_storage_service_privileges {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uid_t uid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen gid_t gid;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const char *uid_source, *gid_source;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *home;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const char *chroot;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen};
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenstruct mail_storage_service_ctx {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen pool_t pool;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct master_service *service;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen const char *default_log_prefix;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct auth_master_connection *conn, *iter_conn;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct auth_master_user_list_ctx *auth_list;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct setting_parser_info **set_roots;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_storage_service_flags flags;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen const char *set_cache_module, *set_cache_service;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct master_service_settings_cache *set_cache;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen pool_t userdb_next_pool;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const **userdb_next_fieldsp;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int debug:1;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen unsigned int log_initialized:1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int config_permission_denied:1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_storage_service_user {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen pool_t pool;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage_service_ctx *service_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage_service_input input;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_storage_service_flags flags;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct ioloop_context *ioloop_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *log_prefix, *auth_token, *auth_user;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *system_groups_user, *uid_source, *gid_source;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_user_settings *user_set;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct setting_parser_info *user_info;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct setting_parser_context *set_parser;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int anonymous:1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int admin:1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct module *mail_storage_service_modules = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmail_user_set_get_mail_debug(const struct setting_parser_info *user_info,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct mail_user_settings *user_set)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct mail_storage_settings *mail_set;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_set = mail_user_set_get_driver_settings(user_info, user_set,
b34fdb68d376d85b4880da4a4bdf67ae726a381bTimo Sirainen MAIL_STORAGE_SET_DRIVER_NAME);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return mail_set->mail_debug;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void set_keyval(struct mail_storage_service_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage_service_user *user,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *key, const char *value)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen const char *str;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (master_service_set_has_config_override(ctx->service, key)) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen /* this setting was already overridden with -o parameter */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_user_set_get_mail_debug(user->user_info,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->user_set)) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_debug("Ignoring overridden (-o) userdb setting: %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen key);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = t_strconcat(key, "=", value, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (settings_parse_line(set_parser, str) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("Invalid userdb input '%s': %s", str,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen settings_parser_get_error(set_parser));
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int set_line(struct mail_storage_service_ctx *ctx,
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen struct mail_storage_service_user *user,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *line)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen bool mail_debug;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen const char *key, *orig_key, *append_value = NULL;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen unsigned int len;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen int ret;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen mail_debug = mail_user_set_get_mail_debug(user->user_info,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen user->user_set);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (strchr(line, '=') == NULL)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen line = t_strconcat(line, "=yes", NULL);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen orig_key = key = t_strcut(line, '=');
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
714d59900e44e6e2dd744bd7b76862e1d11a4f61Timo Sirainen len = strlen(key);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen if (len > 0 && key[len-1] == '+') {
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen /* key+=value */
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen append_value = line + len + 1;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen key = t_strndup(key, len-1);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen }
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen if (!settings_parse_is_valid_key(set_parser, key)) {
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen /* assume it's a plugin setting */
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen key = t_strconcat("plugin/", key, NULL);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen line = t_strconcat("plugin/", line, NULL);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen }
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen if (master_service_set_has_config_override(ctx->service, key)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* this setting was already overridden with -o parameter */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (mail_debug) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_debug("Ignoring overridden (-o) userdb setting: %s",
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen key);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (append_value != NULL) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const void *value;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen enum setting_type type;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen value = settings_parse_get_value(set_parser, key, &type);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (type == SET_STR) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *strp = value;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen line = t_strdup_printf("%s=%s%s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen key, *strp, append_value);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_error("Ignoring %s userdb setting. "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "'+' can only be used for strings.", orig_key);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = settings_parse_line(set_parser, line);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (mail_debug && ret >= 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strstr(key, "pass") != NULL) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* possibly a password field (e.g. imapc_password).
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen hide the value. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen line = t_strconcat(key, "=<hidden>", NULL);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_debug(ret == 0 ?
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Unknown userdb setting: %s" :
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Added userdb setting: %s", line);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return ret;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool validate_chroot(const struct mail_user_settings *user_set,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *dir)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *chroot_dirs;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*dir == '\0')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*user_set->valid_chroot_dirs == '\0')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while (*chroot_dirs != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (**chroot_dirs != '\0' &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen chroot_dirs++;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenuser_reply_handle(struct mail_storage_service_ctx *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage_service_user *user,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct auth_user_reply *reply,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char **error_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *home = reply->home;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *chroot = reply->chroot;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *str, *line, *p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (reply->uid != (uid_t)-1) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (reply->uid == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = "userdb returned 0 as uid";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->uid_source = "userdb lookup";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen set_keyval(ctx, user, "mail_uid", dec2str(reply->uid));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (reply->gid != (uid_t)-1) {
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen user->gid_source = "userdb lookup";
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen set_keyval(ctx, user, "mail_gid", dec2str(reply->gid));
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen }
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (home != NULL && chroot == NULL &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *user->user_set->valid_chroot_dirs != '\0' &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (p = strstr(home, "/./")) != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* wu-ftpd like <chroot>/./<home> - check only if there's even
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen a possibility of using them (non-empty valid_chroot_dirs) */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen chroot = t_strdup_until(home, p);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen home = p + 2;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (home != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen set_keyval(ctx, user, "mail_home", home);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (chroot != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!validate_chroot(user->user_set, chroot)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "userdb returned invalid chroot directory: %s "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(see valid_chroot_dirs setting)", chroot);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen set_keyval(ctx, user, "mail_chroot", chroot);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->anonymous = reply->anonymous;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = array_get(&reply->extra_fields, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen line = str[i];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strncmp(line, "system_groups_user=", 19) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->system_groups_user =
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen p_strdup(user->pool, line + 19);
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen } else if (strncmp(line, "nice=", 5) == 0) {
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen#ifdef HAVE_SETPRIORITY
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen int n = atoi(line + 5);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (n != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (setpriority(PRIO_PROCESS, 0, n) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_error("setpriority(%d) failed: %m", n);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#endif
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(line, "auth_token=", 11) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->auth_token = p_strdup(user->pool, line+11);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen } else if (strncmp(line, "auth_user=", 10) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->auth_user = p_strdup(user->pool, line+10);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(line, "admin=", 6) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->admin = line[6] == 'y' || line[6] == 'Y' ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen line[6] == '1';
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else T_BEGIN {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = set_line(ctx, user, line);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen } T_END;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (ret < 0)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen break;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (ret < 0) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen *error_r = t_strdup_printf("Invalid userdb input '%s': %s",
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen str[i], settings_parser_get_error(user->set_parser));
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainenservice_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen const struct mail_storage_service_input *input,
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen pool_t pool, const char **user,
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen const char *const **fields_r,
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen const char **error_r)
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen{
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen struct auth_user_info info;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *new_username;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memset(&info, 0, sizeof(info));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen info.service = input->service != NULL ? input->service :
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->service->name;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen info.local_ip = input->local_ip;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen info.remote_ip = input->remote_ip;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen info.local_port = input->local_port;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen info.remote_port = input->remote_port;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &new_username, fields_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret > 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (strcmp(*user, new_username) != 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (ctx->debug)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_debug("changed username to %s", new_username);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *user = t_strdup(new_username);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *user = new_username;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else if (ret == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = "Unknown user";
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen else if (**fields_r != NULL) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk *error_r = t_strdup(**fields_r);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = -2;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen } else {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen *error_r = MAIL_ERRSTR_CRITICAL_MSG;
263946a65b625fd4198619a8626db0f36bbafd66Timo Sirainen }
263946a65b625fd4198619a8626db0f36bbafd66Timo Sirainen return ret;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainenstatic bool parse_uid(const char *str, uid_t *uid_r, const char **error_r)
02a6291366caff79793db35d479e2a062bec2af4Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct passwd pw;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (str_to_uid(str, uid_r) == 0)
573085b4b25b0bbae8d27969df2c91702eefa23eTimo Sirainen return TRUE;
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen switch (i_getpwnam(str, &pw)) {
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen case -1:
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen *error_r = t_strdup_printf("getpwnam(%s) failed: %m", str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case 0:
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk *error_r = t_strconcat("Unknown UNIX UID user: ", str, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen default:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *uid_r = pw.pw_uid;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen return TRUE;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen }
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen}
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen
1b04762685272a53643ac2179939537a44c7c044Timo Sirainenstatic bool parse_gid(const char *str, gid_t *gid_r, const char **error_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct group gr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str_to_gid(str, gid_r) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen switch (i_getgrnam(str, &gr)) {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen case -1:
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen *error_r = t_strdup_printf("getgrnam(%s) failed: %m", str);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return FALSE;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen case 0:
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen *error_r = t_strconcat("Unknown UNIX GID group: ", str, NULL);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return FALSE;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen default:
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen *gid_r = gr.gr_gid;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen return TRUE;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic const struct var_expand_table *
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenget_var_expand_table(struct master_service *service,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen struct mail_storage_service_user *user,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen const struct mail_storage_service_input *input,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen const struct mail_storage_service_privileges *priv)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen static struct var_expand_table static_tab[] = {
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { 'u', NULL, "user" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { 'n', NULL, "username" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { 'd', NULL, "domain" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { 's', NULL, "service" },
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { 'l', NULL, "lip" },
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { 'r', NULL, "rip" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { 'p', NULL, "pid" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { 'i', NULL, "uid" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { '\0', NULL, "gid" },
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen { '\0', NULL, "session" },
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { '\0', NULL, "auth_user" },
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { '\0', NULL, "auth_username" },
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { '\0', NULL, "auth_domain" },
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen { '\0', NULL, NULL }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen };
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct var_expand_table *tab;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab = t_malloc(sizeof(static_tab));
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[0].value = input->username;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[1].value = t_strcut(input->username, '@');
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[2].value = strchr(input->username, '@');
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (tab[2].value != NULL) tab[2].value++;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[3].value = service->name;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[4].value = net_ip2addr(&input->local_ip);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[5].value = net_ip2addr(&input->remote_ip);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[6].value = my_pid;
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen tab[7].value = priv == NULL ? NULL :
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen dec2str(priv->uid == (uid_t)-1 ? geteuid() : priv->uid);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[8].value = priv == NULL ? NULL :
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen dec2str(priv->gid == (gid_t)-1 ? getegid() : priv->gid);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[9].value = input->session_id;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (user == NULL || user->auth_user == NULL) {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[10].value = tab[0].value;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[11].value = tab[1].value;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[12].value = tab[2].value;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen } else {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[10].value = user->auth_user;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[11].value = t_strcut(user->auth_user, '@');
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen tab[12].value = strchr(user->auth_user, '@');
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen return tab;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainenconst struct var_expand_table *
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenmail_storage_service_get_var_expand_table(struct mail_storage_service_ctx *ctx,
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen struct mail_storage_service_input *input)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct mail_storage_service_privileges priv;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen memset(&priv, 0, sizeof(priv));
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen priv.uid = (uid_t)-1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen priv.gid = (gid_t)-1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return get_var_expand_table(ctx->service, NULL, input, &priv);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic const char *
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenuser_expand_varstr(struct master_service *service,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct mail_storage_service_user *user,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct mail_storage_service_privileges *priv,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen const char *str)
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen string_t *ret;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (*str == SETTING_STRVAR_EXPANDED[0])
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return str + 1;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen ret = t_str_new(256);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen var_expand(ret, str + 1,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen get_var_expand_table(service, user, &user->input, priv));
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return str_c(ret);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic int
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenservice_parse_privileges(struct mail_storage_service_ctx *ctx,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct mail_storage_service_user *user,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen struct mail_storage_service_privileges *priv_r,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const char **error_r)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct mail_user_settings *set = user->user_set;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen uid_t uid = (uid_t)-1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen gid_t gid = (gid_t)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen memset(priv_r, 0, sizeof(*priv_r));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (*set->mail_uid != '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!parse_uid(set->mail_uid, &uid, error_r)) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen *error_r = t_strdup_printf("%s (from %s)", *error_r,
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen user->uid_source);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return -1;
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (uid < (uid_t)set->first_valid_uid ||
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen (set->last_valid_uid != 0 &&
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen uid > (uid_t)set->last_valid_uid)) {
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen *error_r = t_strdup_printf(
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "Mail access for users with UID %s not permitted "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "(see first_valid_uid in config file, uid from %s).",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen dec2str(uid), user->uid_source);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen priv_r->uid = uid;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen priv_r->uid_source = user->uid_source;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (*set->mail_gid != '\0') {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (!parse_gid(set->mail_gid, &gid, error_r)) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen *error_r = t_strdup_printf("%s (from %s)", *error_r,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->gid_source);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen if (gid < (gid_t)set->first_valid_gid ||
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen (set->last_valid_gid != 0 &&
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen gid > (gid_t)set->last_valid_gid)) {
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen *error_r = t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Mail access for users with GID %s not permitted "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "(see first_valid_gid in config file, gid from %s).",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dec2str(gid), user->gid_source);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen priv_r->gid = gid;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen priv_r->gid_source = user->gid_source;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen /* variable strings are expanded in mail_user_init(),
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen but we need the home and chroot sooner so do them separately here. */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen priv_r->home = user_expand_varstr(ctx->service, user, priv_r,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen user->user_set->mail_home);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen priv_r->chroot = user_expand_varstr(ctx->service, user, priv_r,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen user->user_set->mail_chroot);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic void mail_storage_service_seteuid_root(void)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (seteuid(0) < 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_fatal("mail-storage-service: "
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "Failed to restore temporarily dropped root privileges: "
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "seteuid(0) failed: %m");
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic int
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenservice_drop_privileges(struct mail_storage_service_user *user,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct mail_storage_service_privileges *priv,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen bool disallow_root, bool keep_setuid_root,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen bool setenv_only, const char **error_r)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen const struct mail_user_settings *set = user->user_set;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct restrict_access_settings rset;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen uid_t current_euid, setuid_uid = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen const char *cur_chroot, *error;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen current_euid = geteuid();
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen restrict_access_init(&rset);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen restrict_access_get_env(&rset);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (priv->uid != (uid_t)-1) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.uid = priv->uid;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.uid_source = priv->uid_source;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else if (rset.uid == (uid_t)-1 &&
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen disallow_root && current_euid == 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *error_r = "User is missing UID (see mail_uid setting)";
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (priv->gid != (gid_t)-1) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.gid = priv->gid;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.gid_source = priv->gid_source;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else if (rset.gid == (gid_t)-1 && disallow_root &&
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen set->first_valid_gid > 0 && getegid() == 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *error_r = "User is missing GID (see mail_gid setting)";
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (*set->mail_privileged_group != '\0') {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen &error)) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *error_r = t_strdup_printf(
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "%s (in mail_privileged_group setting)", error);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (*set->mail_access_groups != '\0') {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.extra_groups = t_strconcat(set->mail_access_groups, ",",
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.extra_groups, NULL);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.first_valid_gid = set->first_valid_gid;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.last_valid_gid = set->last_valid_gid;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.chroot_dir = *priv->chroot == '\0' ? NULL : priv->chroot;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen rset.system_groups_user = user->system_groups_user;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen cur_chroot = restrict_access_get_current_chroot();
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (cur_chroot != NULL) {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen /* we're already chrooted. make sure the chroots are equal. */
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (rset.chroot_dir == NULL) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *error_r = "Process is already chrooted, "
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen "can't un-chroot for this user";
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (strcmp(rset.chroot_dir, cur_chroot) != 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *error_r = t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Process is already chrooted to %s, "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "can't chroot to %s", cur_chroot, priv->chroot);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* chrooting to same directory where we're already chrooted */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen rset.chroot_dir = NULL;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (disallow_root &&
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0))) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *error_r = "Mail access not allowed for root";
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen }
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (keep_setuid_root) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (current_euid != rset.uid) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (current_euid != 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* we're changing the UID,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen switch back to root first */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_storage_service_seteuid_root();
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen setuid_uid = rset.uid;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen rset.uid = (uid_t)-1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen disallow_root = FALSE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (!setenv_only) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen restrict_access(&rset, *priv->home == '\0' ? NULL : priv->home,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen disallow_root);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen restrict_access_set_env(&rset);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (setuid_uid != 0 && !setenv_only) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (seteuid(setuid_uid) < 0)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_fatal("mail-storage-service: seteuid(%s) failed: %m",
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen dec2str(setuid_uid));
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic int
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenmail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct mail_storage_service_user *user,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage_service_privileges *priv,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_user **mail_user_r,
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen const char **error_r)
f934b271c69c7b3e5e3bca23ff9b3ab6187262c2Timo Sirainen{
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen const struct mail_storage_settings *mail_set;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen const char *home = priv->home;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct mail_user *mail_user;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* NOTE: if more user initialization is added, add it also to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_user_dup() */
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen mail_user = mail_user_alloc(user->input.username, user->user_info,
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen user->user_set);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen mail_user_set_vars(mail_user, ctx->service->name,
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen &user->input.local_ip, &user->input.remote_ip);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_user->uid = priv->uid == (uid_t)-1 ? geteuid() : priv->uid;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_user->gid = priv->gid == (gid_t)-1 ? getegid() : priv->gid;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_user->anonymous = user->anonymous;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen mail_user->admin = user->admin;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen mail_user->auth_token = p_strdup(mail_user->pool, user->auth_token);
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen mail_user->auth_user = p_strdup(mail_user->pool, user->auth_user);
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen mail_user->session_id =
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen p_strdup(mail_user->pool, user->input.session_id);
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen mail_set = mail_user_set_get_storage_set(mail_user);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen if (mail_set->mail_debug) {
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen string_t *str = t_str_new(64);
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen str_printfa(str, "Effective uid=%s, gid=%s, home=%s",
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen dec2str(geteuid()), dec2str(getegid()), home);
b7835adbfddd8c92b51d6653fb759f963302fa78Timo Sirainen if (*priv->chroot != '\0')
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen str_printfa(str, ", chroot=%s", priv->chroot);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen i_debug("%s", str_c(str));
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen }
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen (user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) == 0) {
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen /* we don't want to write core files to any users' home
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen directories since they could contain information about other
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen users' mails as well. so do no chdiring to home. */
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen } else if (*home != '\0' &&
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen (user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) {
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen /* If possible chdir to home directory, so that core file
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen could be written in case we crash. */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (chdir(home) < 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (errno == EACCES) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_error("%s", eacces_error_get("chdir",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen t_strconcat(home, "/", NULL)));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } if (errno != ENOENT)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_error("chdir(%s) failed: %m", home);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen else if (mail_set->mail_debug)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_debug("Home dir not found: %s", home);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mail_user_init(mail_user, error_r) < 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_user_unref(&mail_user);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES) == 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (mail_namespaces_init(mail_user, error_r) < 0) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen mail_user_unref(&mail_user);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen return -1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen *mail_user_r = mail_user;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return 0;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid mail_storage_service_io_activate_user(struct mail_storage_service_user *user)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen i_set_failure_prefix("%s", user->log_prefix);
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid mail_storage_service_io_deactivate_user(struct mail_storage_service_user *user)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_set_failure_prefix("%s", user->service_ctx->default_log_prefix);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid mail_storage_service_io_deactivate(struct mail_storage_service_ctx *ctx)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_set_failure_prefix("%s", ctx->default_log_prefix);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic void
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenmail_storage_service_init_log(struct mail_storage_service_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct mail_storage_service_user *user,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_storage_service_privileges *priv)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen ctx->log_initialized = TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen T_BEGIN {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen string_t *str;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen str = t_str_new(256);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen var_expand(str, user->user_set->mail_log_prefix,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen get_var_expand_table(ctx->service, user, &user->input, priv));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen user->log_prefix = p_strdup(user->pool, str_c(str));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } T_END;
abb9b8f14e83baca887cf12210bfe480f6cde7a6Timo Sirainen
abb9b8f14e83baca887cf12210bfe480f6cde7a6Timo Sirainen master_service_init_log(ctx->service, user->log_prefix);
abb9b8f14e83baca887cf12210bfe480f6cde7a6Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (master_service_get_client_limit(master_service) == 1)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_set_failure_send_prefix(user->log_prefix);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen user->ioloop_ctx = io_loop_context_new(current_ioloop);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen io_loop_context_add_callbacks(user->ioloop_ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_storage_service_io_activate_user,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_storage_service_io_deactivate_user,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic void mail_storage_service_time_moved(time_t old_time, time_t new_time)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen long diff = new_time - old_time;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (diff > 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (diff > MAX_NOWARN_FORWARD_SECS)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_warning("Time jumped forwards %ld seconds", diff);
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen return;
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen }
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen diff = -diff;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (diff > MAX_TIME_BACKWARDS_SLEEP) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_fatal("Time just moved backwards by %ld seconds. "
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen "This might cause a lot of problems, "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "so I'll just kill myself now. "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "http://wiki2.dovecot.org/TimeMovedBackwards", diff);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } else {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_error("Time just moved backwards by %ld seconds. "
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen "I'll sleep now until we're back in present. "
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen "http://wiki2.dovecot.org/TimeMovedBackwards", diff);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen /* Sleep extra second to make sure usecs also grows. */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen diff++;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen while (diff > 0 && sleep(diff) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* don't use sleep()'s return value, because
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen it could get us to a long loop in case
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen interrupts just keep coming */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen diff = old_time - time(NULL) + 1;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen }
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct mail_storage_service_ctx *
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenmail_storage_service_init(struct master_service *service,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct setting_parser_info *set_roots[],
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen enum mail_storage_service_flags flags)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct mail_storage_service_ctx *ctx;
705f6fbad395e6f014838e797b7dbcaceafd2f1dTimo Sirainen const char *version;
8f5b34c22e4c3bfb35ca13c4744867eb5ddbd3d6Timo Sirainen pool_t pool;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen unsigned int count;
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen version = master_service_get_version_string(service);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen i_fatal("Version mismatch: libdovecot-storage.so is '%s', "
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen "while the running Dovecot binary is '%s'",
95d9395d15540b3a96f75c7f9fd73e6d8ad5e897Timo Sirainen PACKAGE_VERSION, version);
95d9395d15540b3a96f75c7f9fd73e6d8ad5e897Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen if ((flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen geteuid() != 0) {
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen /* service { user } isn't root. the permission drop can't be
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen temporary. */
48ada47cce07fb7195a3437224c7c25f542326b0Timo Sirainen flags &= ~MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)umask(0077);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen io_loop_set_time_moved_callback(current_ioloop,
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen mail_storage_service_time_moved);
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_init();
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mail_storage_register_all();
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen mailbox_list_register_all();
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen pool = pool_alloconly_create("mail storage service", 2048);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx = p_new(pool, struct mail_storage_service_ctx, 1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->pool = pool;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->service = service;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->flags = flags;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen /* @UNSAFE */
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen if (set_roots == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen count = 0;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen else
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen for (count = 0; set_roots[count] != NULL; count++) ;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->set_roots =
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen p_new(pool, const struct setting_parser_info *, count + 2);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->set_roots[0] = &mail_user_setting_parser_info;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (set_roots != NULL) {
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen memcpy(ctx->set_roots + 1, set_roots,
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen sizeof(*ctx->set_roots) * count);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen }
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen /* do all the global initialization. delay initializing plugins until
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen we drop privileges the first time. */
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0) {
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen /* note: we may not have read any settings yet, so this logging
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen may still be going to wrong location */
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen ctx->default_log_prefix =
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen p_strconcat(pool, service->name, ": ", NULL);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen master_service_init_log(service, ctx->default_log_prefix);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen }
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen dict_drivers_register_builtin();
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen return ctx;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct auth_master_connection *
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenmail_storage_service_get_auth_conn(struct mail_storage_service_ctx *ctx)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_assert(ctx->conn != NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return ctx->conn;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic enum mail_storage_service_flags
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenmail_storage_service_input_get_flags(struct mail_storage_service_ctx *ctx,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct mail_storage_service_input *input)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen enum mail_storage_service_flags flags;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen flags = (ctx->flags & ~input->flags_override_remove) |
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen input->flags_override_add;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (input->no_userdb_lookup) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* FIXME: for API backwards compatibility only */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen flags &= ~MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return flags;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenint mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen const struct mail_storage_service_input *input,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen pool_t pool,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct setting_parser_info **user_info_r,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const struct setting_parser_context **parser_r,
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen const char **error_r)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen struct master_service_settings_input set_input;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen const struct setting_parser_info *const *roots;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen struct master_service_settings_output set_output;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen const struct dynamic_settings_parser *dyn_parsers;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen enum mail_storage_service_flags flags;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen unsigned int i;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen ctx->config_permission_denied = FALSE;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen flags = input == NULL ? ctx->flags :
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen mail_storage_service_input_get_flags(ctx, input);
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen memset(&set_input, 0, sizeof(set_input));
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen set_input.roots = ctx->set_roots;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen set_input.preserve_user = TRUE;
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen /* settings reader may exec doveconf, which is going to clear
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen environment, and if we're not doing a userdb lookup we want to
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen use $HOME */
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen set_input.preserve_home =
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen (flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen set_input.use_sysexits =
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen (flags & MAIL_STORAGE_SERVICE_FLAG_USE_SYSEXITS) != 0;
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen if (input != NULL) {
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen set_input.module = input->module;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen set_input.service = input->service;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen set_input.username = input->username;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen set_input.local_ip = input->local_ip;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen set_input.remote_ip = input->remote_ip;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen }
97180ea9c26c4de0807daaad21e03c80643b09fdTimo Sirainen if (input == NULL) {
88b315f36ba082708ab6f53ea1924c54d9be0aefTimo Sirainen /* global settings read - don't create a cache for thi */
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen } else if (ctx->set_cache == NULL) {
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen ctx->set_cache_module = p_strdup(ctx->pool, set_input.module);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen ctx->set_cache_service = p_strdup(ctx->pool, set_input.service);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen ctx->set_cache = master_service_settings_cache_init(
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->service, set_input.module, set_input.service);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } else {
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen /* already looked up settings at least once.
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen we really shouldn't be execing anymore. */
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen set_input.never_exec = TRUE;
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen }
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen dyn_parsers = mail_storage_get_dynamic_parsers(pool);
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen if (null_strcmp(set_input.module, ctx->set_cache_module) == 0 &&
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen null_strcmp(set_input.service, ctx->set_cache_service) == 0 &&
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen ctx->set_cache != NULL) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (master_service_settings_cache_read(ctx->set_cache,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &set_input, dyn_parsers,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen parser_r, error_r) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *error_r = t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Error reading configuration: %s", *error_r);
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen return -1;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen } else {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen settings_parser_dyn_update(pool, &set_input.roots, dyn_parsers);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (master_service_settings_read(ctx->service, &set_input,
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen &set_output, error_r) < 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen *error_r = t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Error reading configuration: %s", *error_r);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ctx->config_permission_denied =
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen set_output.permission_denied;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return -1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *parser_r = ctx->service->set_parser;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen roots = settings_parser_get_roots(*parser_r);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen for (i = 0; roots[i] != NULL; i++) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (strcmp(roots[i]->module_name,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen mail_user_setting_parser_info.module_name) == 0) {
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen *user_info_r = roots[i];
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen return 0;
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen }
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen }
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen i_unreached();
7e95ba7f38b9b421287d36c6152f8a9e6b9f225bTimo Sirainen return -1;
608bdb7f008cd5cd332d727018a9e8173abec998Timo Sirainen}
608bdb7f008cd5cd332d727018a9e8173abec998Timo Sirainen
608bdb7f008cd5cd332d727018a9e8173abec998Timo Sirainenvoid mail_storage_service_set_auth_conn(struct mail_storage_service_ctx *ctx,
608bdb7f008cd5cd332d727018a9e8173abec998Timo Sirainen struct auth_master_connection *conn)
608bdb7f008cd5cd332d727018a9e8173abec998Timo Sirainen{
608bdb7f008cd5cd332d727018a9e8173abec998Timo Sirainen i_assert(ctx->conn == NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(mail_user_auth_master_conn == NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen ctx->conn = conn;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_user_auth_master_conn = conn;
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen}
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainenstatic void
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainenmail_storage_service_first_init(struct mail_storage_service_ctx *ctx,
2eb0402a28bd0422e0170160808c67d6c7274689Timo Sirainen const struct setting_parser_info *user_info,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_user_settings *user_set)
{
enum auth_master_flags flags = 0;
ctx->debug = mail_user_set_get_mail_debug(user_info, user_set);
if (ctx->debug)
flags |= AUTH_MASTER_FLAG_DEBUG;
if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_IDLE_TIMEOUT) != 0)
flags |= AUTH_MASTER_FLAG_NO_IDLE_TIMEOUT;
mail_storage_service_set_auth_conn(ctx,
auth_master_init(user_set->auth_socket_path, flags));
}
static int
mail_storage_service_load_modules(struct mail_storage_service_ctx *ctx,
const struct setting_parser_info *user_info,
const struct mail_user_settings *user_set,
const char **error_r)
{
struct module_dir_load_settings mod_set;
if (*user_set->mail_plugins == '\0')
return 0;
if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS) != 0)
return 0;
memset(&mod_set, 0, sizeof(mod_set));
mod_set.abi_version = DOVECOT_ABI_VERSION;
mod_set.binary_name = master_service_get_name(ctx->service);
mod_set.setting_name = "mail_plugins";
mod_set.require_init_funcs = TRUE;
mod_set.debug = mail_user_set_get_mail_debug(user_info, user_set);
return module_dir_try_load_missing(&mail_storage_service_modules,
user_set->mail_plugin_dir,
user_set->mail_plugins,
&mod_set, error_r);
}
static int extra_field_key_cmp_p(const char *const *s1, const char *const *s2)
{
const char *p1 = *s1, *p2 = *s2;
for (; *p1 == *p2; p1++, p2++) {
if (*p1 == '\0')
return 0;
}
if (*p1 == '=')
return -1;
if (*p2 == '=')
return 1;
return *p1 - *p2;
}
static void
mail_storage_service_set_log_prefix(struct mail_storage_service_ctx *ctx,
const struct mail_user_settings *user_set,
struct mail_storage_service_user *user,
const struct mail_storage_service_input *input,
const struct mail_storage_service_privileges *priv)
{
string_t *str;
str = t_str_new(256);
var_expand(str, user_set->mail_log_prefix,
get_var_expand_table(ctx->service, user, input, priv));
i_set_failure_prefix("%s", str_c(str));
}
static const char *mail_storage_service_generate_session_id(pool_t pool)
{
guid_128_t guid;
string_t *str = str_new(pool, MAX_BASE64_ENCODED_SIZE(sizeof(guid)));
guid_128_generate(guid);
base64_encode(guid, sizeof(guid), str);
/* remove the trailing "==" */
i_assert(str_data(str)[str_len(str)-2] == '=');
str_truncate(str, str_len(str)-2);
return str_c(str);
}
static int
mail_storage_service_lookup_real(struct mail_storage_service_ctx *ctx,
const struct mail_storage_service_input *input,
bool update_log_prefix,
struct mail_storage_service_user **user_r,
const char **error_r)
{
enum mail_storage_service_flags flags;
struct mail_storage_service_user *user;
const char *username = input->username;
const struct setting_parser_info *user_info;
const struct mail_user_settings *user_set;
const char *const *userdb_fields, *error;
struct auth_user_reply reply;
const struct setting_parser_context *set_parser;
void **sets;
pool_t user_pool, temp_pool;
int ret = 1;
user_pool = pool_alloconly_create(MEMPOOL_GROWING"mail storage service user", 1024*6);
flags = mail_storage_service_input_get_flags(ctx, input);
if ((flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
geteuid() != 0) {
/* we dropped privileges only temporarily. switch back to root
before reading settings, so we'll definitely have enough
permissions to connect to the config socket. */
mail_storage_service_seteuid_root();
}
if (mail_storage_service_read_settings(ctx, input, user_pool,
&user_info, &set_parser,
&error) < 0) {
if (ctx->config_permission_denied) {
/* just restart and maybe next time we will open the
config socket before dropping privileges */
i_fatal("%s", error);
}
i_error("%s", error);
pool_unref(&user_pool);
*error_r = MAIL_ERRSTR_CRITICAL_MSG;
return -1;
}
if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0 &&
!ctx->log_initialized) {
/* initialize logging again, in case we only read the
settings for the first above */
ctx->log_initialized = TRUE;
master_service_init_log(ctx->service,
t_strconcat(ctx->service->name, ": ", NULL));
update_log_prefix = TRUE;
}
sets = master_service_settings_parser_get_others(master_service,
set_parser);
user_set = sets[0];
if (update_log_prefix)
mail_storage_service_set_log_prefix(ctx, user_set, NULL, input, NULL);
if (ctx->conn == NULL)
mail_storage_service_first_init(ctx, user_info, user_set);
/* load global plugins */
if (mail_storage_service_load_modules(ctx, user_info, user_set, &error) < 0) {
i_error("%s", error);
pool_unref(&user_pool);
*error_r = MAIL_ERRSTR_CRITICAL_MSG;
return -1;
}
if (ctx->userdb_next_pool == NULL)
temp_pool = pool_alloconly_create("userdb lookup", 2048);
else {
temp_pool = ctx->userdb_next_pool;
ctx->userdb_next_pool = NULL;
pool_ref(temp_pool);
}
if ((flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) {
ret = service_auth_userdb_lookup(ctx, input, temp_pool,
&username, &userdb_fields,
error_r);
if (ret <= 0) {
pool_unref(&temp_pool);
pool_unref(&user_pool);
return ret;
}
if (ctx->userdb_next_fieldsp != NULL)
*ctx->userdb_next_fieldsp = userdb_fields;
} else {
userdb_fields = input->userdb_fields;
}
user = p_new(user_pool, struct mail_storage_service_user, 1);
user->service_ctx = ctx;
user->pool = user_pool;
user->input = *input;
user->input.userdb_fields = NULL;
user->input.username = p_strdup(user_pool, username);
user->input.session_id = p_strdup(user_pool, input->session_id);
if (user->input.session_id == NULL) {
user->input.session_id =
mail_storage_service_generate_session_id(user_pool);
}
user->user_info = user_info;
user->flags = flags;
user->set_parser = settings_parser_dup(set_parser, user_pool);
if (!settings_parser_check(user->set_parser, user_pool, &error))
i_panic("settings_parser_check() failed: %s", error);
sets = master_service_settings_parser_get_others(master_service,
user->set_parser);
user->user_set = sets[0];
user->gid_source = "mail_gid setting";
user->uid_source = "mail_uid setting";
if ((flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0)
(void)settings_parse_line(user->set_parser, "mail_debug=yes");
if ((flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) {
const char *home = getenv("HOME");
if (home != NULL)
set_keyval(ctx, user, "mail_home", home);
}
if (userdb_fields != NULL) {
auth_user_fields_parse(userdb_fields, temp_pool, &reply);
array_sort(&reply.extra_fields, extra_field_key_cmp_p);
if (user_reply_handle(ctx, user, &reply, &error) < 0) {
i_error("Invalid settings in userdb: %s", error);
*error_r = ERRSTR_INVALID_USER_SETTINGS;
ret = -2;
}
}
pool_unref(&temp_pool);
/* load per-user plugins */
if (ret > 0) {
if (mail_storage_service_load_modules(ctx, user_info,
user->user_set,
&error) < 0) {
i_error("%s", error);
*error_r = MAIL_ERRSTR_CRITICAL_MSG;
ret = -2;
}
}
*user_r = user;
return ret;
}
int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx,
const struct mail_storage_service_input *input,
struct mail_storage_service_user **user_r,
const char **error_r)
{
char *old_log_prefix = i_strdup(i_get_failure_prefix());
bool update_log_prefix;
int ret;
if (io_loop_get_current_context(current_ioloop) == NULL) {
/* no user yet. log prefix should be just "imap:" or something
equally unhelpful. we don't know the proper log format yet,
but initialize it to something better until we know it. */
i_set_failure_prefix("%s(%s%s,%s)",
master_service_get_name(ctx->service), input->username,
input->session_id == NULL ? "" :
t_strdup_printf(",%s", input->session_id),
input->remote_ip.family == 0 ? "" :
t_strdup_printf(",%s", net_ip2addr(&input->remote_ip)));
update_log_prefix = TRUE;
} else {
/* we might be here because we're doing a user lookup for a
shared user. the log prefix is likely already usable, so
just append our own without replacing the whole thing. */
i_set_failure_prefix("%suser-lookup(%s)",
old_log_prefix, input->username);
update_log_prefix = FALSE;
}
ret = mail_storage_service_lookup_real(ctx, input, update_log_prefix,
user_r, error_r);
i_set_failure_prefix("%s", old_log_prefix);
i_free(old_log_prefix);
return ret;
}
void mail_storage_service_save_userdb_fields(struct mail_storage_service_ctx *ctx,
pool_t pool, const char *const **userdb_fields_r)
{
i_assert(pool != NULL);
i_assert(userdb_fields_r != NULL);
ctx->userdb_next_pool = pool;
ctx->userdb_next_fieldsp = userdb_fields_r;
*userdb_fields_r = NULL;
}
static int
mail_storage_service_next_real(struct mail_storage_service_ctx *ctx,
struct mail_storage_service_user *user,
struct mail_user **mail_user_r)
{
struct mail_storage_service_privileges priv;
const char *error;
unsigned int len;
bool disallow_root =
(user->flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0;
bool temp_priv_drop =
(user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0;
bool use_chroot;
if (service_parse_privileges(ctx, user, &priv, &error) < 0) {
i_error("%s", error);
return -2;
}
if (*priv.home != '/' && *priv.home != '\0') {
i_error("Relative home directory paths not supported: %s",
priv.home);
return -2;
}
/* we can't chroot if we want to switch between users. there's
not much point either (from security point of view). but if we're
already chrooted, we'll just have to continue and hope that the
current chroot is the same as the wanted chroot */
use_chroot = !temp_priv_drop ||
restrict_access_get_current_chroot() != NULL;
len = strlen(priv.chroot);
if (len > 2 && strcmp(priv.chroot + len - 2, "/.") == 0 &&
strncmp(priv.home, priv.chroot, len - 2) == 0) {
/* mail_chroot = /chroot/. means that the home dir already
contains the chroot dir. remove it from home. */
if (use_chroot) {
priv.home += len - 2;
if (*priv.home == '\0')
priv.home = "/";
priv.chroot = t_strndup(priv.chroot, len - 2);
set_keyval(ctx, user, "mail_home", priv.home);
set_keyval(ctx, user, "mail_chroot", priv.chroot);
}
} else if (len > 0 && !use_chroot) {
/* we're not going to chroot. fix home directory so we can
access it. */
if (*priv.home == '\0' || strcmp(priv.home, "/") == 0)
priv.home = priv.chroot;
else
priv.home = t_strconcat(priv.chroot, priv.home, NULL);
priv.chroot = "";
set_keyval(ctx, user, "mail_home", priv.home);
}
if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0)
mail_storage_service_init_log(ctx, user, &priv);
if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) {
if (service_drop_privileges(user, &priv,
disallow_root, temp_priv_drop,
FALSE, &error) < 0) {
i_error("Couldn't drop privileges: %s", error);
return -1;
}
if (!temp_priv_drop ||
(user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) != 0)
restrict_access_allow_coredumps(TRUE);
}
/* privileges are dropped. initialize plugins that haven't been
initialized yet. */
module_dir_init(mail_storage_service_modules);
if (mail_storage_service_init_post(ctx, user, &priv,
mail_user_r, &error) < 0) {
i_error("User initialization failed: %s", error);
return -2;
}
return 0;
}
int mail_storage_service_next(struct mail_storage_service_ctx *ctx,
struct mail_storage_service_user *user,
struct mail_user **mail_user_r)
{
char *old_log_prefix = i_strdup(i_get_failure_prefix());
int ret;
mail_storage_service_set_log_prefix(ctx, user->user_set, user,
&user->input, NULL);
i_set_failure_prefix("%s", old_log_prefix);
ret = mail_storage_service_next_real(ctx, user, mail_user_r);
if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) != 0)
i_set_failure_prefix("%s", old_log_prefix);
i_free(old_log_prefix);
return ret;
}
void mail_storage_service_restrict_setenv(struct mail_storage_service_ctx *ctx,
struct mail_storage_service_user *user)
{
struct mail_storage_service_privileges priv;
const char *error;
if (service_parse_privileges(ctx, user, &priv, &error) < 0)
i_fatal("user %s: %s", user->input.username, error);
if (service_drop_privileges(user, &priv,
FALSE, FALSE, TRUE, &error) < 0)
i_fatal("user %s: %s", user->input.username, error);
}
int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx,
const struct mail_storage_service_input *input,
struct mail_storage_service_user **user_r,
struct mail_user **mail_user_r,
const char **error_r)
{
struct mail_storage_service_user *user;
int ret;
ret = mail_storage_service_lookup(ctx, input, &user, error_r);
if (ret <= 0)
return ret;
ret = mail_storage_service_next(ctx, user, mail_user_r);
if (ret < 0) {
mail_storage_service_user_free(&user);
*error_r = ret == -2 ? ERRSTR_INVALID_USER_SETTINGS :
MAIL_ERRSTR_CRITICAL_MSG;
return ret;
}
*user_r = user;
return 1;
}
void mail_storage_service_user_free(struct mail_storage_service_user **_user)
{
struct mail_storage_service_user *user = *_user;
*_user = NULL;
if (user->ioloop_ctx != NULL) {
io_loop_context_remove_callbacks(user->ioloop_ctx,
mail_storage_service_io_activate_user,
mail_storage_service_io_deactivate_user, user);
io_loop_context_unref(&user->ioloop_ctx);
}
settings_parser_deinit(&user->set_parser);
pool_unref(&user->pool);
}
void mail_storage_service_init_settings(struct mail_storage_service_ctx *ctx,
const struct mail_storage_service_input *input)
{
const struct setting_parser_info *user_info;
const struct mail_user_settings *user_set;
const struct setting_parser_context *set_parser;
const char *error;
pool_t temp_pool;
void **sets;
if (ctx->conn != NULL)
return;
temp_pool = pool_alloconly_create("service all settings", 4096);
if (mail_storage_service_read_settings(ctx, input, temp_pool,
&user_info, &set_parser,
&error) < 0)
i_fatal("%s", error);
sets = master_service_settings_parser_get_others(master_service,
set_parser);
user_set = sets[0];
mail_storage_service_first_init(ctx, user_info, user_set);
pool_unref(&temp_pool);
}
static int
mail_storage_service_all_iter_deinit(struct mail_storage_service_ctx *ctx)
{
int ret = 0;
if (ctx->auth_list != NULL) {
ret = auth_master_user_list_deinit(&ctx->auth_list);
auth_master_deinit(&ctx->iter_conn);
}
return ret;
}
void mail_storage_service_all_init(struct mail_storage_service_ctx *ctx)
{
enum auth_master_flags flags = 0;
(void)mail_storage_service_all_iter_deinit(ctx);
mail_storage_service_init_settings(ctx, NULL);
/* create a new connection, because the iteration might take a while
and we might want to do USER lookups during it, which don't mix
well in the same connection. */
if (ctx->debug)
flags |= AUTH_MASTER_FLAG_DEBUG;
ctx->iter_conn = auth_master_init(auth_master_get_socket_path(ctx->conn),
flags);
ctx->auth_list = auth_master_user_list_init(ctx->iter_conn, "", NULL);
}
int mail_storage_service_all_next(struct mail_storage_service_ctx *ctx,
const char **username_r)
{
i_assert((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0);
*username_r = auth_master_user_list_next(ctx->auth_list);
if (*username_r != NULL)
return 1;
return mail_storage_service_all_iter_deinit(ctx);
}
void mail_storage_service_deinit(struct mail_storage_service_ctx **_ctx)
{
struct mail_storage_service_ctx *ctx = *_ctx;
*_ctx = NULL;
(void)mail_storage_service_all_iter_deinit(ctx);
if (ctx->conn != NULL) {
if (mail_user_auth_master_conn == ctx->conn)
mail_user_auth_master_conn = NULL;
auth_master_deinit(&ctx->conn);
}
if (ctx->set_cache != NULL)
master_service_settings_cache_deinit(&ctx->set_cache);
pool_unref(&ctx->pool);
module_dir_unload(&mail_storage_service_modules);
mail_storage_deinit();
dict_drivers_unregister_builtin();
}
void **mail_storage_service_user_get_set(struct mail_storage_service_user *user)
{
return master_service_settings_parser_get_others(master_service,
user->set_parser);
}
const struct mail_storage_settings *
mail_storage_service_user_get_mail_set(struct mail_storage_service_user *user)
{
return mail_user_set_get_driver_settings(
user->user_info, user->user_set,
MAIL_STORAGE_SET_DRIVER_NAME);
}
const struct mail_storage_service_input *
mail_storage_service_user_get_input(struct mail_storage_service_user *user)
{
return &user->input;
}
struct setting_parser_context *
mail_storage_service_user_get_settings_parser(struct mail_storage_service_user *user)
{
return user->set_parser;
}
void *mail_storage_service_get_settings(struct master_service *service)
{
void **sets, *set;
T_BEGIN {
sets = master_service_settings_get_others(service);
set = sets[1];
} T_END;
return set;
}