mail-storage-service.c revision 48ada47cce07fb7195a3437224c7c25f542326b0
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "lib.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "ioloop.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "array.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "hostpid.h"
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen#include "module-dir.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "restrict-access.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "eacces-error.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "str.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "var-expand.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "dict.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "settings-parser.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-master.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "master-service-private.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "master-service-settings.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "mail-user.h"
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen#include "mail-namespace.h"
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen#include "mail-storage.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include "mail-storage-service.h"
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include <stdlib.h>
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include <sys/stat.h>
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include <pwd.h>
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#include <grp.h>
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#ifdef HAVE_SYS_TIME_H
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen# include <sys/time.h>
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#endif
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#ifdef HAVE_SYS_RESOURCE_H
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen# include <sys/resource.h>
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#endif
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen/* If time moves backwards more than this, kill ourself instead of sleeping. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#define MAX_TIME_BACKWARDS_SLEEP 5
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#define MAX_NOWARN_FORWARD_SECS 10
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstruct mail_storage_service_ctx {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct master_service *service;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct auth_master_connection *conn;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct auth_master_user_list_ctx *auth_list;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct setting_parser_info **set_roots;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mail_storage_service_flags flags;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int debug:1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen};
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstruct mail_storage_service_user {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pool_t pool;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mail_storage_service_input input;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *system_groups_user;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct mail_user_settings *user_set;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct setting_parser_info *user_info;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct setting_parser_context *set_parser;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen};
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic struct module *modules = NULL;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void set_keyval(struct setting_parser_context *set_parser,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *key, const char *value)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *str;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str = t_strconcat(key, "=", value, NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (settings_parse_line(set_parser, str) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_fatal("Invalid userdb input '%s': %s", str,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen settings_parser_get_error(set_parser));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainenstatic bool validate_chroot(const struct mail_user_settings *user_set,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *dir)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *const *chroot_dirs;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen if (*dir == '\0')
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*user_set->valid_chroot_dirs == '\0')
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen while (*chroot_dirs != NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (**chroot_dirs != '\0' &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen chroot_dirs++;
b104354c4a829e828c361e4a167bf7106d124174Timo Sirainen }
b104354c4a829e828c361e4a167bf7106d124174Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenuser_reply_handle(struct mail_storage_service_user *user,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct auth_user_reply *reply,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char **error_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct setting_parser_context *set_parser = user->set_parser;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *const *str, *p, *line, *key;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int i, count;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret = 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (reply->uid != (uid_t)-1) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (reply->uid == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *error_r = "userdb returned 0 as uid";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_keyval(set_parser, "mail_uid", dec2str(reply->uid));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (reply->gid != (uid_t)-1)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_keyval(set_parser, "mail_gid", dec2str(reply->gid));
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (reply->home != NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_keyval(set_parser, "mail_home", reply->home);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (reply->chroot != NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!validate_chroot(user->user_set, reply->chroot)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *error_r = t_strdup_printf(
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "userdb returned invalid chroot directory: %s "
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "(see valid_chroot_dirs setting)",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen reply->chroot);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_keyval(set_parser, "mail_chroot", reply->chroot);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str = array_get(&reply->extra_fields, &count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = 0; i < count && ret == 0; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line = str[i];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (strncmp(line, "system_groups_user=", 19) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen user->system_groups_user =
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen p_strdup(user->pool, line + 19);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else if (strncmp(line, "nice=", 5) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#ifdef HAVE_SETPRIORITY
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen int n = atoi(line + 5);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (n != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (setpriority(PRIO_PROCESS, 0, n) < 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_error("setpriority(%d) failed: %m", n);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen#endif
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else T_BEGIN {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (strncmp(line, "mail=", 5) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line = t_strconcat("mail_location=",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line + 5, NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else if ((p = strchr(str[i], '=')) == NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line = t_strconcat(str[i], "=yes", NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line = str[i];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen key = t_strcut(line, '=');
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!settings_parse_is_valid_key(set_parser, key)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* assume it's a plugin setting */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen line = t_strconcat("plugin/", line, NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = settings_parse_line(set_parser, line);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } T_END;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ret < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *error_r = t_strdup_printf("Invalid userdb input '%s': %s",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str[i], settings_parser_get_error(set_parser));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic int
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenservice_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct mail_storage_service_input *input,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen pool_t pool, const char **user,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *const **fields_r,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char **error_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct auth_user_info info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *new_username;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen int ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen memset(&info, 0, sizeof(info));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen info.service = ctx->service->name;
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen info.local_ip = input->local_ip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen info.remote_ip = input->remote_ip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen &new_username, fields_r);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ret > 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (strcmp(*user, new_username) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->debug)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_debug("changed username to %s", new_username);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *user = t_strdup(new_username);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *user = new_username;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else if (ret == 0)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *error_r = "unknown user";
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *error_r = "userdb lookup failed";
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic bool parse_uid(const char *str, uid_t *uid_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct passwd *pw;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen char *p;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*str >= '0' && *str <= '9') {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *uid_r = (uid_t)strtoul(str, &p, 10);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*p == '\0')
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen pw = getpwnam(str);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (pw == NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return FALSE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen *uid_r = pw->pw_uid;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic bool parse_gid(const char *str, gid_t *gid_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct group *gr;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen char *p;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*str >= '0' && *str <= '9') {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen *gid_r = (gid_t)strtoul(str, &p, 10);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*p == '\0')
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen gr = getgrnam(str);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (gr == NULL)
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen return FALSE;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen *gid_r = gr->gr_gid;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return TRUE;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen}
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainenservice_drop_privileges(const struct mail_user_settings *set,
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen const char *system_groups_user,
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen const char *home, const char *chroot,
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen bool disallow_root, bool keep_setuid_root)
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen{
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen struct restrict_access_settings rset;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen uid_t current_euid, setuid_uid = 0;
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen current_euid = geteuid();
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen restrict_access_init(&rset);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (*set->mail_uid != '\0') {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (!parse_uid(set->mail_uid, &rset.uid))
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen i_fatal("Unknown mail_uid user: %s", set->mail_uid);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (rset.uid < (uid_t)set->first_valid_uid ||
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen (set->last_valid_uid != 0 &&
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen rset.uid > (uid_t)set->last_valid_uid)) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen i_fatal("Mail access for users with UID %s "
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen "not permitted (see first_valid_uid in config file).",
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen dec2str(rset.uid));
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (*set->mail_gid != '\0') {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (!parse_gid(set->mail_gid, &rset.gid))
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen i_fatal("Unknown mail_gid group: %s", set->mail_gid);
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen if (rset.gid < (gid_t)set->first_valid_gid ||
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen (set->last_valid_gid != 0 &&
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen rset.gid > (gid_t)set->last_valid_gid)) {
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen i_fatal("Mail access for users with GID %s "
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen "not permitted (see first_valid_gid in config file).",
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen dec2str(rset.gid));
7da99e97d68f854b8726755d36dfb24b6cf08701Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*set->mail_privileged_group != '\0') {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid)) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_fatal("Unknown mail_privileged_group: %s",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set->mail_gid);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*set->mail_access_groups != '\0')
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen rset.extra_groups = set->mail_access_groups;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen rset.first_valid_gid = set->first_valid_gid;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen rset.last_valid_gid = set->last_valid_gid;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen /* we can't chroot if we want to switch between users. there's not
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen much point either (from security point of view) */
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen rset.chroot_dir = *chroot == '\0' || keep_setuid_root ? NULL : chroot;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen rset.system_groups_user = system_groups_user;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (disallow_root &&
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0)))
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_fatal("Mail access not allowed for root");
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (keep_setuid_root) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (current_euid != rset.uid) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (current_euid != 0) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen /* we're changing the UID,
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen switch back to root first */
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (seteuid(0) < 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_fatal("seteuid(0) failed: %m");
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen setuid_uid = rset.uid;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen rset.uid = (uid_t)-1;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen disallow_root = FALSE;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen restrict_access(&rset, *home == '\0' ? NULL : home, disallow_root);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (setuid_uid != 0) {
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (seteuid(setuid_uid) < 0)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_fatal("seteuid(%s) failed: %m", dec2str(setuid_uid));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic int
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenmail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_storage_service_user *user,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char *home, struct mail_user **mail_user_r,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char **error_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct mail_storage_settings *mail_set;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_user *mail_user;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_user = mail_user_alloc(user->input.username, user->user_info,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen user->user_set);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_user_set_vars(mail_user, geteuid(), ctx->service->name,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen &user->input.local_ip, &user->input.remote_ip);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_set = mail_user_set_get_storage_set(mail_user);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (mail_set->mail_debug) {
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen i_debug("Effective uid=%s, gid=%s, home=%s",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen dec2str(geteuid()), dec2str(getegid()), home);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* we don't want to write core files to any users' home
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen directories since they could contain information about other
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen users' mails as well. so do no chdiring to home. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else if (*home != '\0' &&
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* If possible chdir to home directory, so that core file
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen could be written in case we crash. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (chdir(home) < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (errno == EACCES) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_error("%s", eacces_error_get("chdir",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen t_strconcat(home, "/", NULL)));
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen } if (errno != ENOENT)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_error("chdir(%s) failed: %m", home);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen else if (mail_set->mail_debug)
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen i_debug("Home dir not found: %s", home);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (mail_user_init(mail_user, error_r) < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_user_unref(&mail_user);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (mail_namespaces_init(mail_user, error_r) < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_user_unref(&mail_user);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *mail_user_r = mail_user;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 0;
31ed209b28f30bcc2ce20de07aaa43d432126e24Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic const struct var_expand_table *
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenget_var_expand_table(struct master_service *service,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mail_storage_service_input *input)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen static struct var_expand_table static_tab[] = {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 'u', NULL, "user" },
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 'n', NULL, "username" },
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen { 'd', NULL, "domain" },
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 's', NULL, "service" },
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 'l', NULL, "lip" },
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 'r', NULL, "rip" },
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 'p', NULL, "pid" },
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen { 'i', NULL, "uid" },
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen { '\0', NULL, NULL }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen };
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen struct var_expand_table *tab;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab = t_malloc(sizeof(static_tab));
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[0].value = input->username;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[1].value = t_strcut(input->username, '@');
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[2].value = strchr(input->username, '@');
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen if (tab[2].value != NULL) tab[2].value++;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[3].value = service->name;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[4].value = net_ip2addr(&input->local_ip);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[5].value = net_ip2addr(&input->remote_ip);
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[6].value = my_pid;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen tab[7].value = dec2str(geteuid());
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return tab;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic const char *
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenuser_expand_varstr(struct master_service *service,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_storage_service_input *input, const char *str)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen string_t *ret;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (*str == SETTING_STRVAR_EXPANDED[0])
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return str + 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ret = t_str_new(256);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen var_expand(ret, str + 1, get_var_expand_table(service, input));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return str_c(ret);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenmail_storage_service_init_log(struct master_service *service,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_storage_service_user *user)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct mail_user_settings *user_set;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen void **sets;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen sets = master_service_settings_get_others(service);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen user_set = sets[0];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen T_BEGIN {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen string_t *str;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen str = t_str_new(256);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen var_expand(str, user->user_set->mail_log_prefix,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen get_var_expand_table(service, &user->input));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen master_service_init_log(service, str_c(str));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } T_END;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void mail_storage_service_time_moved(time_t old_time, time_t new_time)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen long diff = new_time - old_time;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (diff > 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (diff > MAX_NOWARN_FORWARD_SECS)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_warning("Time jumped forwards %ld seconds", diff);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen diff = -diff;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (diff > MAX_TIME_BACKWARDS_SLEEP) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_fatal("Time just moved backwards by %ld seconds. "
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "This might cause a lot of problems, "
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "so I'll just kill myself now. "
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "http://wiki.dovecot.org/TimeMovedBackwards", diff);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen } else {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_error("Time just moved backwards by %ld seconds. "
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "I'll sleep now until we're back in present. "
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen "http://wiki.dovecot.org/TimeMovedBackwards", diff);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* Sleep extra second to make sure usecs also grows. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen diff++;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen while (diff > 0 && sleep(diff) != 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* don't use sleep()'s return value, because
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen it could get us to a long loop in case
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen interrupts just keep coming */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen diff = old_time - time(NULL) + 1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstruct mail_storage_service_ctx *
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenmail_storage_service_init(struct master_service *service,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct setting_parser_info *set_roots[],
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen enum mail_storage_service_flags flags)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct mail_storage_service_ctx *ctx;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen (void)umask(0077);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen io_loop_set_time_moved_callback(current_ioloop,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_storage_service_time_moved);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_storage_init();
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail_storage_register_all();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mailbox_list_register_all();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx = i_new(struct mail_storage_service_ctx, 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->service = service;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->flags = flags;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* @UNSAFE */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (set_roots == NULL)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen count = 0;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen else
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (count = 0; set_roots[count] != NULL; count++) ;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->set_roots = i_new(const struct setting_parser_info *, count + 2);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->set_roots[0] = &mail_user_setting_parser_info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen memcpy(ctx->set_roots + 1, set_roots, sizeof(*ctx->set_roots) * count);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* do all the global initialization. delay initializing plugins until
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen we drop privileges the first time. */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if ((flags & MAIL_STORAGE_SERVICE_NO_LOG_INIT) == 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen master_service_init_log(service,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen t_strconcat(service->name, ": ", NULL));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
08837f59c1466ec0f533f120b167f2a3e87da738Timo Sirainen dict_drivers_register_builtin();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ctx;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstruct auth_master_connection *
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenmail_storage_service_get_auth_conn(struct mail_storage_service_ctx *ctx)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
115cf0320f679e4e63db25e7f44f47977b8338deTimo Sirainen i_assert(ctx->conn != NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return ctx->conn;
115cf0320f679e4e63db25e7f44f47977b8338deTimo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainensettings_parser_update_children_parent(struct setting_parser_info *parent,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen pool_t pool)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct setting_define *new_defs;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct setting_parser_info *new_info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int i, count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (count = 0; parent->defines[count].key != NULL; count++) ;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_defs = p_new(pool, struct setting_define, count + 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen memcpy(new_defs, parent->defines, sizeof(*new_defs) * count);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen parent->defines = new_defs;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = 0; i < count; i++) {
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen if (new_defs[i].list_info == NULL ||
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen new_defs[i].list_info->parent == NULL)
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen continue;
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen new_info = p_new(pool, struct setting_parser_info, 1);
459f60325f94f486ef057241b42d8a9e9c376fb4Timo Sirainen *new_info = *new_defs[i].list_info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_info->parent = parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_defs[i].list_info = new_info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainenstatic struct setting_parser_info *
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainendyn_parsers_update_parent(pool_t pool,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct master_service_settings_input *input)
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen{
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen const struct setting_parser_info *old_parent, **new_roots;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct setting_parser_info *new_parent, *new_info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen struct dynamic_settings_parser *new_dyn_parsers;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen unsigned int i, count;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* settings_parser_info_update() modifies the parent structure.
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen since we may be using the same structure later, we want it to be
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen in its original state, so we'll have to copy all structures. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen old_parent = input->dyn_parsers[0].info->parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_parent = p_new(pool, struct setting_parser_info, 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *new_parent = *old_parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen settings_parser_update_children_parent(new_parent, pool);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* update root */
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (count = 0; input->roots[count] != NULL; count++) ;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen new_roots = p_new(pool, const struct setting_parser_info *, count + 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = 0; i < count; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (input->roots[i] == old_parent)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_roots[i] = new_parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen else
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_roots[i] = input->roots[i];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen input->roots = new_roots;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen /* update parent in dyn_parsers */
c2fbbf7515aa419dc8b2d62a3c2bb0471d51a391Timo Sirainen for (count = 0; input->dyn_parsers[count].name != NULL; count++) ;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_dyn_parsers = p_new(pool, struct dynamic_settings_parser, count + 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = 0; i < count; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_dyn_parsers[i] = input->dyn_parsers[i];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_info = p_new(pool, struct setting_parser_info, 1);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *new_info = *input->dyn_parsers[i].info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_info->parent = new_parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen new_dyn_parsers[i].info = new_info;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen input->dyn_parsers = new_dyn_parsers;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return new_parent;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainenint mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct mail_storage_service_input *input,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen pool_t pool,
3a508ab3b10ff08889f3046a6bbf8553b55e3d44Timo Sirainen const struct setting_parser_info **user_info_r,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const char **error_r)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct master_service_settings_input set_input;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen unsigned int i;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen memset(&set_input, 0, sizeof(set_input));
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.roots = ctx->set_roots;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.dyn_parsers = mail_storage_get_dynamic_parsers();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* settings reader may exec doveconf, which is going to clear
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen environment, and if we're not doing a userdb lookup we want to
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen use $HOME */
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen set_input.preserve_home =
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.dyn_parsers_parent =
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen dyn_parsers_update_parent(pool, &set_input);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (input != NULL) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.module = input->module;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.service = input->service;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.username = input->username;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.local_ip = input->local_ip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen set_input.remote_ip = input->remote_ip;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (master_service_settings_read(ctx->service, &set_input,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen error_r) < 0) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *error_r = t_strdup_printf("Error reading configuration: %s",
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *error_r);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen for (i = 0; ctx->set_roots[i] != NULL; i++) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen if (ctx->set_roots[i] == &mail_user_setting_parser_info) {
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen *user_info_r = set_input.roots[i];
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return 0;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen }
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_unreached();
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen return -1;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen}
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenstatic void
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainenmail_storage_service_first_init(struct mail_storage_service_ctx *ctx,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct setting_parser_info *user_info,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen const struct mail_user_settings *user_set)
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen{
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen const struct mail_storage_settings *mail_set;
da2f9bc5d477bdfee1773d7dcbcdd5a293c7d48cTimo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen i_assert(ctx->conn == NULL);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen mail_set = mail_user_set_get_driver_settings(user_info, user_set,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen MAIL_STORAGE_SET_DRIVER_NAME);
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->debug = mail_set->mail_debug;
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->conn = auth_master_init(user_set->auth_socket_path,
d43bed2d458520fd01c28229ce2b178a4593a4a7Timo Sirainen ctx->debug);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(mail_user_auth_master_conn == NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mail_user_auth_master_conn = ctx->conn;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenmail_storage_service_load_modules(struct mail_storage_service_ctx *ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct mail_user_settings *user_set)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *version;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (*user_set->mail_plugins == '\0')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen version = master_service_get_version_string(ctx->service);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen modules = module_dir_load_missing(modules, user_set->mail_plugin_dir,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen user_set->mail_plugins, TRUE,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen version);
}
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)
{
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;
struct auth_user_reply reply;
void **sets;
pool_t user_pool, temp_pool;
int ret = 1;
user_pool = pool_alloconly_create("mail storage service user", 1024*4);
if (mail_storage_service_read_settings(ctx, input, user_pool,
&user_info, error_r) < 0) {
pool_unref(&user_pool);
return -1;
}
sets = settings_parser_get_list(ctx->service->set_parser);
user_set = sets[1];
if (ctx->conn == NULL)
mail_storage_service_first_init(ctx, user_info, user_set);
/* load global plugins */
mail_storage_service_load_modules(ctx, user_set);
temp_pool = pool_alloconly_create("userdb lookup", 1024);
if ((ctx->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;
}
} else {
userdb_fields = input->userdb_fields;
}
user = p_new(user_pool, struct mail_storage_service_user, 1);
memset(user_r, 0, sizeof(user_r));
user->pool = user_pool;
user->input = *input;
user->input.userdb_fields = NULL;
user->input.username = p_strdup(user_pool, username);
user->user_info = user_info;
user->set_parser =
settings_parser_dup(ctx->service->set_parser, user_pool);
sets = settings_parser_get_list(user->set_parser);
user->user_set = sets[1];
if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) {
const char *home = getenv("HOME");
if (home != NULL)
set_keyval(user->set_parser, "mail_home", home);
}
if (userdb_fields != NULL) {
auth_user_fields_parse(userdb_fields, temp_pool, &reply);
if (user_reply_handle(user, &reply, error_r) < 0)
ret = -1;
}
pool_unref(&temp_pool);
/* load per-user plugins */
mail_storage_service_load_modules(ctx, user->user_set);
*user_r = user;
return ret;
}
int mail_storage_service_next(struct mail_storage_service_ctx *ctx,
struct mail_storage_service_user *user,
struct mail_user **mail_user_r,
const char **error_r)
{
const struct mail_user_settings *user_set = user->user_set;
const char *home, *chroot;
unsigned int len;
bool temp_priv_drop =
(ctx->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP);
/* variable strings are expanded in mail_user_init(),
but we need the home and chroot sooner so do them separately here. */
home = user_expand_varstr(ctx->service, &user->input,
user_set->mail_home);
chroot = user_expand_varstr(ctx->service, &user->input,
user_set->mail_chroot);
if (*home != '/' && *home != '\0') {
i_error("user %s: Relative home directory paths not supported: "
"%s", user->input.username, home);
return -1;
}
if ((ctx->flags & MAIL_STORAGE_SERVICE_NO_LOG_INIT) == 0)
mail_storage_service_init_log(ctx->service, user);
if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) {
service_drop_privileges(user_set, user->system_groups_user,
home, chroot,
(ctx->flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0,
temp_priv_drop);
if (!temp_priv_drop ||
(ctx->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(modules);
/* we couldn't do chrooting, so if chrooting was enabled fix
the home directory */
len = strlen(chroot);
if (len > 2 && strcmp(chroot + len - 2, "/.") == 0 &&
strncmp(home, chroot, len - 2) == 0) {
/* home dir already contains the chroot dir */
if (!temp_priv_drop) {
home += len - 2;
if (*home == '\0')
home = "/";
set_keyval(user->set_parser, "mail_home", home);
chroot = t_strndup(chroot, len - 2);
}
} else if (len > 0 && temp_priv_drop) {
set_keyval(user->set_parser, "mail_home",
t_strconcat(chroot, "/", home, NULL));
}
if (mail_storage_service_init_post(ctx, user, home,
mail_user_r, error_r) < 0)
return -1;
return 0;
}
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;
const char *error;
int ret;
ret = mail_storage_service_lookup(ctx, input, &user, &error);
if (ret <= 0) {
*error_r = t_strdup_printf("User lookup failed: %s", error);
return ret;
}
if (mail_storage_service_next(ctx, user, mail_user_r, &error) < 0) {
mail_storage_service_user_free(&user);
*error_r = t_strdup_printf("User init failed: %s", error);
return -1;
}
*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;
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 char *error;
void **sets;
pool_t temp_pool;
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, &error) < 0)
i_fatal("%s", error);
sets = settings_parser_get_list(ctx->service->set_parser);
user_set = sets[1];
mail_storage_service_first_init(ctx, user_info, user_set);
pool_unref(&temp_pool);
}
unsigned int
mail_storage_service_all_init(struct mail_storage_service_ctx *ctx)
{
if (ctx->auth_list != NULL)
(void)auth_master_user_list_deinit(&ctx->auth_list);
mail_storage_service_init_settings(ctx, NULL);
ctx->auth_list = auth_master_user_list_init(ctx->conn);
return auth_master_user_list_count(ctx->auth_list);
}
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 auth_master_user_list_deinit(&ctx->auth_list);
}
void mail_storage_service_deinit(struct mail_storage_service_ctx **_ctx)
{
struct mail_storage_service_ctx *ctx = *_ctx;
*_ctx = NULL;
if (ctx->auth_list != NULL)
(void)auth_master_user_list_deinit(&ctx->auth_list);
if (ctx->conn != NULL) {
if (mail_user_auth_master_conn == ctx->conn)
mail_user_auth_master_conn = NULL;
auth_master_deinit(&ctx->conn);
}
i_free(ctx);
module_dir_unload(&modules);
mail_storage_deinit();
dict_drivers_unregister_builtin();
}
void **mail_storage_service_user_get_set(struct mail_storage_service_user *user)
{
return settings_parser_get_list(user->set_parser) + 1;
}
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;
}