Mercurial > dovecot > original-hg > dovecot-1.2
view src/master/master-settings.c @ 2798:54b29901a793 HEAD
Added simple LRU cache for auth requests. Currently only for sql passdb.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 21 Oct 2004 05:23:09 +0300 |
parents | 8ba8f672dc3e |
children | 100ecc609dd1 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "common.h" #include "istream.h" #include "safe-mkdir.h" #include "unlink-directory.h" #include "settings.h" #include <stdio.h> #include <stddef.h> #include <unistd.h> #include <fcntl.h> #include <pwd.h> enum settings_type { SETTINGS_TYPE_ROOT, SETTINGS_TYPE_SERVER, SETTINGS_TYPE_AUTH, SETTINGS_TYPE_AUTH_SOCKET, SETTINGS_TYPE_NAMESPACE, SETTINGS_TYPE_SOCKET }; struct settings_parse_ctx { enum settings_type type, parent_type; enum mail_protocol protocol; struct server_settings *root, *server; struct auth_settings *auth; struct socket_settings *socket; struct auth_socket_settings *auth_socket; struct namespace_settings *namespace; int level; }; #define DEF(type, name) \ { type, #name, offsetof(struct settings, name) } static struct setting_def setting_defs[] = { /* common */ DEF(SET_STR, base_dir), DEF(SET_STR, log_path), DEF(SET_STR, info_log_path), DEF(SET_STR, log_timestamp), /* general */ DEF(SET_STR, protocols), DEF(SET_STR, listen), DEF(SET_STR, ssl_listen), DEF(SET_BOOL, ssl_disable), DEF(SET_STR, ssl_ca_file), DEF(SET_STR, ssl_cert_file), DEF(SET_STR, ssl_key_file), DEF(SET_STR, ssl_parameters_file), DEF(SET_STR, ssl_parameters_regenerate), DEF(SET_STR, ssl_cipher_list), DEF(SET_BOOL, ssl_verify_client_cert), DEF(SET_BOOL, disable_plaintext_auth), DEF(SET_BOOL, verbose_ssl), /* login */ DEF(SET_STR, login_dir), DEF(SET_STR, login_executable), DEF(SET_STR, login_user), DEF(SET_STR, login_greeting), DEF(SET_BOOL, login_process_per_connection), DEF(SET_BOOL, login_chroot), DEF(SET_BOOL, login_greeting_capability), DEF(SET_INT, login_process_size), DEF(SET_INT, login_processes_count), DEF(SET_INT, login_max_processes_count), DEF(SET_INT, login_max_logging_users), /* mail */ DEF(SET_STR, valid_chroot_dirs), DEF(SET_STR, mail_chroot), DEF(SET_INT, max_mail_processes), DEF(SET_BOOL, verbose_proctitle), DEF(SET_INT, first_valid_uid), DEF(SET_INT, last_valid_uid), DEF(SET_INT, first_valid_gid), DEF(SET_INT, last_valid_gid), DEF(SET_STR, mail_extra_groups), DEF(SET_STR, default_mail_env), DEF(SET_STR, mail_cache_fields), DEF(SET_STR, mail_never_cache_fields), DEF(SET_INT, mailbox_idle_check_interval), DEF(SET_BOOL, mail_full_filesystem_access), DEF(SET_INT, mail_max_keyword_length), DEF(SET_BOOL, mail_save_crlf), DEF(SET_BOOL, mail_read_mmaped), DEF(SET_BOOL, mmap_disable), DEF(SET_BOOL, mmap_no_write), DEF(SET_STR, lock_method), DEF(SET_BOOL, maildir_stat_dirs), DEF(SET_BOOL, maildir_copy_with_hardlinks), DEF(SET_BOOL, maildir_check_content_changes), DEF(SET_STR, mbox_read_locks), DEF(SET_STR, mbox_write_locks), DEF(SET_INT, mbox_lock_timeout), DEF(SET_INT, mbox_dotlock_change_timeout), DEF(SET_BOOL, mbox_dirty_syncs), DEF(SET_BOOL, mbox_lazy_writes), DEF(SET_INT, umask), DEF(SET_BOOL, mail_drop_priv_before_exec), DEF(SET_STR, mail_executable), DEF(SET_INT, mail_process_size), DEF(SET_BOOL, mail_use_modules), DEF(SET_STR, mail_modules), DEF(SET_STR, mail_log_prefix), /* imap */ DEF(SET_INT, imap_max_line_length), DEF(SET_STR, imap_capability), DEF(SET_STR, imap_client_workarounds), /* pop3 */ DEF(SET_BOOL, pop3_no_flag_updates), DEF(SET_BOOL, pop3_enable_last), DEF(SET_STR, pop3_client_workarounds), { 0, NULL, 0 } }; #undef DEF #define DEF(type, name) \ { type, #name, offsetof(struct auth_settings, name) } static struct setting_def auth_setting_defs[] = { DEF(SET_STR, mechanisms), DEF(SET_STR, realms), DEF(SET_STR, default_realm), DEF(SET_STR, userdb), DEF(SET_STR, passdb), DEF(SET_INT, cache_size), DEF(SET_INT, cache_ttl), DEF(SET_STR, executable), DEF(SET_STR, user), DEF(SET_STR, chroot), DEF(SET_STR, username_chars), DEF(SET_STR, username_translation), DEF(SET_STR, anonymous_username), DEF(SET_BOOL, verbose), DEF(SET_BOOL, debug), DEF(SET_BOOL, ssl_require_client_cert), DEF(SET_INT, count), DEF(SET_INT, process_size), { 0, NULL, 0 } }; #undef DEF #define DEF(type, name) \ { type, #name, offsetof(struct socket_settings, name) } static struct setting_def socket_setting_defs[] = { DEF(SET_STR, path), DEF(SET_INT, mode), DEF(SET_STR, user), DEF(SET_STR, group), { 0, NULL, 0 } }; #undef DEF #define DEF(type, name) \ { type, #name, offsetof(struct auth_socket_settings, name) } static struct setting_def auth_socket_setting_defs[] = { DEF(SET_STR, type), { 0, NULL, 0 } }; #undef DEF #define DEF(type, name) \ { type, #name, offsetof(struct namespace_settings, name) } static struct setting_def namespace_setting_defs[] = { DEF(SET_STR, type), DEF(SET_STR, separator), DEF(SET_STR, prefix), DEF(SET_STR, location), DEF(SET_BOOL, inbox), DEF(SET_BOOL, hidden), { 0, NULL, 0 } }; struct settings default_settings = { MEMBER(server) NULL, MEMBER(protocol) 0, /* common */ MEMBER(base_dir) PKG_RUNDIR, MEMBER(log_path) NULL, MEMBER(info_log_path) NULL, MEMBER(log_timestamp) DEFAULT_FAILURE_STAMP_FORMAT, /* general */ MEMBER(protocols) "imap imaps", MEMBER(listen) "*", MEMBER(ssl_listen) NULL, #ifdef HAVE_SSL MEMBER(ssl_disable) FALSE, #else MEMBER(ssl_disable) TRUE, #endif MEMBER(ssl_ca_file) NULL, MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem", MEMBER(ssl_key_file) SSLDIR"/private/dovecot.pem", MEMBER(ssl_parameters_file) "ssl-parameters.dat", MEMBER(ssl_parameters_regenerate) 24, MEMBER(ssl_cipher_list) NULL, MEMBER(ssl_verify_client_cert) FALSE, MEMBER(disable_plaintext_auth) TRUE, MEMBER(verbose_ssl) FALSE, /* login */ MEMBER(login_dir) "login", MEMBER(login_executable) NULL, MEMBER(login_user) "dovecot", MEMBER(login_greeting) "Dovecot ready.", MEMBER(login_process_per_connection) TRUE, MEMBER(login_chroot) TRUE, MEMBER(login_greeting_capability) FALSE, MEMBER(login_process_size) 32, MEMBER(login_processes_count) 3, MEMBER(login_max_processes_count) 128, MEMBER(login_max_logging_users) 256, /* mail */ MEMBER(valid_chroot_dirs) NULL, MEMBER(mail_chroot) NULL, MEMBER(max_mail_processes) 1024, MEMBER(verbose_proctitle) FALSE, MEMBER(first_valid_uid) 500, MEMBER(last_valid_uid) 0, MEMBER(first_valid_gid) 1, MEMBER(last_valid_gid) 0, MEMBER(mail_extra_groups) NULL, MEMBER(default_mail_env) NULL, MEMBER(mail_cache_fields) "flags", MEMBER(mail_never_cache_fields) "imap.envelope", MEMBER(mailbox_idle_check_interval) 30, MEMBER(mail_full_filesystem_access) FALSE, MEMBER(mail_max_keyword_length) 50, MEMBER(mail_save_crlf) FALSE, MEMBER(mail_read_mmaped) FALSE, MEMBER(mmap_disable) FALSE, #ifdef MMAP_CONFLICTS_WRITE MEMBER(mmap_no_write) TRUE, #else MEMBER(mmap_no_write) FALSE, #endif MEMBER(lock_method) "fcntl", MEMBER(maildir_stat_dirs) FALSE, MEMBER(maildir_copy_with_hardlinks) FALSE, MEMBER(maildir_check_content_changes) FALSE, MEMBER(mbox_read_locks) "fcntl", MEMBER(mbox_write_locks) "dotlock fcntl", MEMBER(mbox_lock_timeout) 300, MEMBER(mbox_dotlock_change_timeout) 30, MEMBER(mbox_dirty_syncs) TRUE, MEMBER(mbox_lazy_writes) TRUE, MEMBER(umask) 0077, MEMBER(mail_drop_priv_before_exec) FALSE, MEMBER(mail_executable) PKG_LIBEXECDIR"/imap", MEMBER(mail_process_size) 256, MEMBER(mail_use_modules) FALSE, MEMBER(mail_modules) MODULEDIR"/imap", MEMBER(mail_log_prefix) "%Up(%u): ", /* imap */ MEMBER(imap_max_line_length) 65536, MEMBER(imap_capability) NULL, MEMBER(imap_client_workarounds) "outlook-idle", /* pop3 */ MEMBER(pop3_no_flag_updates) FALSE, MEMBER(pop3_enable_last) FALSE, MEMBER(pop3_client_workarounds) NULL, /* .. */ MEMBER(login_uid) 0, MEMBER(listen_fd) -1, MEMBER(ssl_listen_fd) -1 }; struct auth_settings default_auth_settings = { MEMBER(parent) NULL, MEMBER(next) NULL, MEMBER(name) NULL, MEMBER(mechanisms) "plain", MEMBER(realms) NULL, MEMBER(default_realm) NULL, MEMBER(userdb) "passwd", MEMBER(passdb) "pam", MEMBER(cache_size) 0, MEMBER(cache_ttl) 3600, MEMBER(executable) PKG_LIBEXECDIR"/dovecot-auth", MEMBER(user) "root", MEMBER(chroot) NULL, MEMBER(username_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@", MEMBER(username_translation) "", MEMBER(anonymous_username) "anonymous", MEMBER(verbose) FALSE, MEMBER(debug) FALSE, MEMBER(ssl_require_client_cert) FALSE, MEMBER(count) 1, MEMBER(process_size) 256, /* .. */ MEMBER(uid) 0, MEMBER(gid) 0, MEMBER(sockets) NULL }; static pool_t settings_pool, settings2_pool; struct server_settings *settings_root = NULL; static void fix_base_path(struct settings *set, const char **str) { if (*str != NULL && **str != '\0' && **str != '/') { *str = p_strconcat(settings_pool, set->base_dir, "/", *str, NULL); } } static int get_login_uid(struct settings *set) { struct passwd *pw; if ((pw = getpwnam(set->login_user)) == NULL) { i_error("Login user doesn't exist: %s", set->login_user); return FALSE; } if (set->server->login_gid == 0) set->server->login_gid = pw->pw_gid; else if (set->server->login_gid != pw->pw_gid) { i_error("All login process users must belong to same group " "(%s vs %s)", dec2str(set->server->login_gid), dec2str(pw->pw_gid)); return FALSE; } set->login_uid = pw->pw_uid; return TRUE; } static int auth_settings_verify(struct auth_settings *auth) { struct passwd *pw; if ((pw = getpwnam(auth->user)) == NULL) { i_error("Auth user doesn't exist: %s", auth->user); return FALSE; } if (auth->parent->defaults->login_uid == pw->pw_uid && master_uid != pw->pw_uid) { i_error("login_user %s (uid %s) must not be same as auth_user", auth->user, dec2str(pw->pw_uid)); return FALSE; } auth->uid = pw->pw_uid; auth->gid = pw->pw_gid; if (access(auth->executable, X_OK) < 0) { i_error("Can't use auth executable %s: %m", auth->executable); return FALSE; } fix_base_path(auth->parent->defaults, &auth->chroot); if (auth->chroot != NULL && access(auth->chroot, X_OK) < 0) { i_error("Can't access auth chroot directory %s: %m", auth->chroot); return FALSE; } if (auth->ssl_require_client_cert) { /* if we require valid cert, make sure we also ask for it */ if (auth->parent->pop3 != NULL) auth->parent->pop3->ssl_verify_client_cert = TRUE; if (auth->parent->imap != NULL) auth->parent->imap->ssl_verify_client_cert = TRUE; } return TRUE; } static int namespace_settings_verify(struct namespace_settings *ns) { const char *name; name = ns->prefix != NULL ? ns->prefix : ""; if (ns->separator != NULL && ns->separator[0] != '\0' && ns->separator[1] != '\0') { i_error("Namespace '%s': " "Hierarchy separator must be only one character long", name); return FALSE; } return TRUE; } static const char *get_directory(const char *path) { char *str, *p; str = t_strdup_noconst(path); p = strrchr(str, '/'); if (p == NULL) return "."; else { *p = '\0'; return str; } } static int settings_is_active(struct settings *set) { if (set->protocol == MAIL_PROTOCOL_IMAP) { if (strstr(set->protocols, "imap") == NULL) return FALSE; } else { if (strstr(set->protocols, "pop3") == NULL) return FALSE; } return TRUE; } static int settings_have_connect_sockets(struct settings *set) { struct auth_settings *auth; struct server_settings *server; for (server = set->server; server != NULL; server = server->next) { for (auth = server->auths; auth != NULL; auth = auth->next) { if (auth->sockets != NULL && strcmp(auth->sockets->type, "connect") == 0) return TRUE; } } return FALSE; } static int settings_verify(struct settings *set) { const char *dir; if (!get_login_uid(set)) return FALSE; if (access(t_strcut(set->mail_executable, ' '), X_OK) < 0) { i_error("Can't use mail executable %s: %m", t_strcut(set->mail_executable, ' ')); return FALSE; } #ifdef HAVE_MODULES if (set->mail_use_modules && access(set->mail_modules, R_OK | X_OK) < 0) { i_error("Can't access mail module directory: %s: %m", set->mail_modules); return FALSE; } #else if (set->mail_use_modules) { i_warning("Module support wasn't built into Dovecot, " "ignoring mail_use_modules setting"); } #endif if (set->log_path != NULL && access(set->log_path, W_OK) < 0) { dir = get_directory(set->log_path); if (access(dir, W_OK) < 0) { i_error("Can't write to log directory %s: %m", dir); return FALSE; } } if (set->info_log_path != NULL && access(set->info_log_path, W_OK) < 0) { dir = get_directory(set->info_log_path); if (access(dir, W_OK) < 0) { i_error("Can't write to info log directory %s: %m", dir); return FALSE; } } #ifdef HAVE_SSL if (!set->ssl_disable) { if (set->ssl_ca_file != NULL && access(set->ssl_ca_file, R_OK) < 0) { i_fatal("Can't use SSL CA file %s: %m", set->ssl_ca_file); } if (access(set->ssl_cert_file, R_OK) < 0) { i_error("Can't use SSL certificate %s: %m", set->ssl_cert_file); return FALSE; } if (access(set->ssl_key_file, R_OK) < 0) { i_error("Can't use SSL key file %s: %m", set->ssl_key_file); return FALSE; } } #endif /* fix relative paths */ fix_base_path(set, &set->ssl_parameters_file); fix_base_path(set, &set->login_dir); /* since they're under /var/run by default, they may have been deleted. */ if (safe_mkdir(set->base_dir, 0700, master_uid, getegid()) == 0) { i_warning("Corrected permissions for base directory %s", set->base_dir); } /* wipe out contents of login directory, if it exists. except if we're using external authentication - then we would otherwise wipe existing auth sockets */ if (!settings_have_connect_sockets(set)) { if (unlink_directory(set->login_dir, FALSE) < 0) { i_error("unlink_directory() failed for %s: %m", set->login_dir); return FALSE; } } if (safe_mkdir(set->login_dir, 0750, master_uid, set->server->login_gid) == 0) { i_warning("Corrected permissions for login directory %s", set->login_dir); } if (set->max_mail_processes < 1) { i_error("max_mail_processes must be at least 1"); return FALSE; } if (set->last_valid_uid != 0 && set->first_valid_uid > set->last_valid_uid) { i_error("first_valid_uid can't be larger than last_valid_uid"); return FALSE; } if (set->last_valid_gid != 0 && set->first_valid_gid > set->last_valid_gid) { i_error("first_valid_gid can't be larger than last_valid_gid"); return FALSE; } if (access(set->login_executable, X_OK) < 0) { i_error("Can't use login executable %s: %m", set->login_executable); return FALSE; } if (set->login_processes_count < 1) { i_error("login_processes_count must be at least 1"); return FALSE; } if (set->login_max_logging_users < 1) { i_error("login_max_logging_users must be at least 1"); return FALSE; } return TRUE; } static struct auth_settings * auth_settings_new(struct server_settings *server, const char *name) { struct auth_settings *auth; auth = p_new(settings_pool, struct auth_settings, 1); /* copy defaults */ *auth = server->auth_defaults; auth->parent = server; auth->name = p_strdup(settings_pool, name); auth->next = server->auths; server->auths = auth; return auth; } static struct auth_settings * parse_new_auth(struct server_settings *server, const char *name, const char **errormsg) { struct auth_settings *auth; if (strchr(name, '/') != NULL) { *errormsg = "Authentication process name must not contain '/'"; return NULL; } for (auth = server->auths; auth != NULL; auth = auth->next) { if (strcmp(auth->name, name) == 0) { *errormsg = "Authentication process already exists " "with the same name"; return NULL; } } return auth_settings_new(server, name); } static struct auth_socket_settings * auth_socket_settings_new(struct auth_settings *auth, const char *type) { struct auth_socket_settings *as, **as_p; as = p_new(settings_pool, struct auth_socket_settings, 1); as->parent = auth; as->type = str_lcase(p_strdup(settings_pool, type)); as_p = &auth->sockets; while (*as_p != NULL) as_p = &(*as_p)->next; *as_p = as; return as; } static struct auth_socket_settings * parse_new_auth_socket(struct auth_settings *auth, const char *name, const char **errormsg) { if (strcmp(name, "connect") != 0 && strcmp(name, "listen") != 0) { *errormsg = "Unknown auth socket type"; return NULL; } if ((auth->sockets != NULL && strcmp(name, "connect") == 0) || (auth->sockets != NULL && strcmp(auth->sockets->type, "listen") == 0)) { *errormsg = "With connect auth socket no other sockets " "can be used in same auth section"; return NULL; } return auth_socket_settings_new(auth, name); } static struct namespace_settings * namespace_settings_new(struct server_settings *server, const char *type) { struct namespace_settings *ns, **ns_p; ns = p_new(settings_pool, struct namespace_settings, 1); ns->parent = server; ns->type = str_lcase(p_strdup(settings_pool, type)); ns_p = &server->namespaces; while (*ns_p != NULL) ns_p = &(*ns_p)->next; *ns_p = ns; return ns; } static struct namespace_settings * parse_new_namespace(struct server_settings *server, const char *name, const char **errormsg) { if (strcasecmp(name, "private") != 0 && strcasecmp(name, "shared") != 0 && strcasecmp(name, "public") != 0) { *errormsg = "Unknown namespace type"; return NULL; } return namespace_settings_new(server, name); } static const char *parse_setting(const char *key, const char *value, void *context) { struct settings_parse_ctx *ctx = context; const char *error; /* backwards compatibility */ if (strcmp(key, "auth") == 0) { ctx->auth = parse_new_auth(ctx->server, value, &error); return ctx->auth == NULL ? error : NULL; } if (strcmp(key, "login") == 0) { i_warning("Ignoring deprecated 'login' section handling. " "Use protocol imap/pop3 { .. } instead. " "Some settings may have been read incorrectly."); return NULL; } switch (ctx->type) { case SETTINGS_TYPE_ROOT: case SETTINGS_TYPE_SERVER: error = NULL; if (ctx->protocol == MAIL_PROTOCOL_ANY || ctx->protocol == MAIL_PROTOCOL_IMAP) { error = parse_setting_from_defs(settings_pool, setting_defs, ctx->server->imap, key, value); } if (error == NULL && (ctx->protocol == MAIL_PROTOCOL_ANY || ctx->protocol == MAIL_PROTOCOL_POP3)) { error = parse_setting_from_defs(settings_pool, setting_defs, ctx->server->pop3, key, value); } if (error == NULL) return NULL; if (strncmp(key, "auth_", 5) == 0) { return parse_setting_from_defs(settings_pool, auth_setting_defs, ctx->auth, key + 5, value); } return error; case SETTINGS_TYPE_AUTH: if (strncmp(key, "auth_", 5) == 0) key += 5; return parse_setting_from_defs(settings_pool, auth_setting_defs, ctx->auth, key, value); case SETTINGS_TYPE_AUTH_SOCKET: return parse_setting_from_defs(settings_pool, auth_socket_setting_defs, ctx->auth_socket, key, value); case SETTINGS_TYPE_NAMESPACE: return parse_setting_from_defs(settings_pool, namespace_setting_defs, ctx->namespace, key, value); case SETTINGS_TYPE_SOCKET: return parse_setting_from_defs(settings_pool, socket_setting_defs, ctx->socket, key, value); } i_unreached(); } static struct server_settings * create_new_server(const char *name, struct settings *imap_defaults, struct settings *pop3_defaults) { struct server_settings *server; server = p_new(settings_pool, struct server_settings, 1); server->name = p_strdup(settings_pool, name); server->imap = p_new(settings_pool, struct settings, 1); server->pop3 = p_new(settings_pool, struct settings, 1); server->auth_defaults = default_auth_settings; *server->imap = *imap_defaults; *server->pop3 = *pop3_defaults; server->imap->server = server; server->imap->protocol = MAIL_PROTOCOL_IMAP; server->imap->login_executable = PKG_LIBEXECDIR"/imap-login"; server->imap->mail_executable = PKG_LIBEXECDIR"/imap"; server->imap->mail_modules = MODULEDIR"/imap"; server->pop3->server = server; server->pop3->protocol = MAIL_PROTOCOL_POP3; server->pop3->login_executable = PKG_LIBEXECDIR"/pop3-login"; server->pop3->mail_executable = PKG_LIBEXECDIR"/pop3"; server->pop3->mail_modules = MODULEDIR"/pop3"; return server; } static int parse_section(const char *type, const char *name, void *context, const char **errormsg) { struct settings_parse_ctx *ctx = context; struct server_settings *server; if (type == NULL) { /* section closing */ if (--ctx->level > 0) { ctx->type = ctx->parent_type; ctx->protocol = MAIL_PROTOCOL_ANY; switch (ctx->type) { case SETTINGS_TYPE_AUTH_SOCKET: ctx->parent_type = SETTINGS_TYPE_AUTH; break; default: ctx->parent_type = SETTINGS_TYPE_ROOT; break; } } else { ctx->type = SETTINGS_TYPE_ROOT; ctx->server = ctx->root; ctx->auth = &ctx->root->auth_defaults; ctx->namespace = NULL; } return TRUE; } ctx->level++; ctx->parent_type = ctx->type; if (strcmp(type, "server") == 0) { if (ctx->type != SETTINGS_TYPE_ROOT) { *errormsg = "Server section not allowed here"; return FALSE; } ctx->type = SETTINGS_TYPE_SERVER; ctx->server = create_new_server(name, ctx->server->imap, ctx->server->pop3); server = ctx->root; while (server->next != NULL) server = server->next; server->next = ctx->server; return TRUE; } if (strcmp(type, "protocol") == 0) { if ((ctx->type != SETTINGS_TYPE_ROOT && ctx->type != SETTINGS_TYPE_SERVER) || ctx->level != 1) { *errormsg = "Protocol section not allowed here"; return FALSE; } if (strcmp(name, "imap") == 0) ctx->protocol = MAIL_PROTOCOL_IMAP; else if (strcmp(name, "pop3") == 0) ctx->protocol = MAIL_PROTOCOL_POP3; else { *errormsg = "Unknown protocol name"; return FALSE; } return TRUE; } if (strcmp(type, "auth") == 0) { if (ctx->type != SETTINGS_TYPE_ROOT && ctx->type != SETTINGS_TYPE_SERVER) { *errormsg = "Auth section not allowed here"; return FALSE; } ctx->type = SETTINGS_TYPE_AUTH; ctx->auth = parse_new_auth(ctx->server, name, errormsg); return ctx->auth != NULL; } if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "socket") == 0) { ctx->type = SETTINGS_TYPE_AUTH_SOCKET; ctx->auth_socket = parse_new_auth_socket(ctx->auth, name, errormsg); return ctx->auth_socket != NULL; } if (ctx->type == SETTINGS_TYPE_AUTH_SOCKET) { ctx->type = SETTINGS_TYPE_SOCKET; if (strcmp(type, "master") == 0) { ctx->socket = &ctx->auth_socket->master; return TRUE; } if (strcmp(type, "client") == 0) { ctx->socket = &ctx->auth_socket->client; return TRUE; } } if (strcmp(type, "namespace") == 0) { if (ctx->type != SETTINGS_TYPE_ROOT && ctx->type != SETTINGS_TYPE_SERVER) { *errormsg = "Namespace section not allowed here"; return FALSE; } ctx->type = SETTINGS_TYPE_NAMESPACE; ctx->namespace = parse_new_namespace(ctx->server, name, errormsg); return ctx->namespace != NULL; } *errormsg = "Unknown section type"; return FALSE; } int master_settings_read(const char *path, int nochecks) { struct settings_parse_ctx ctx; struct server_settings *server, *prev; struct auth_settings *auth; struct namespace_settings *ns; pool_t temp; memset(&ctx, 0, sizeof(ctx)); p_clear(settings_pool); ctx.type = SETTINGS_TYPE_ROOT; ctx.protocol = MAIL_PROTOCOL_ANY; ctx.server = ctx.root = create_new_server("default", &default_settings, &default_settings); ctx.auth = &ctx.server->auth_defaults; if (!settings_read(path, NULL, parse_setting, parse_section, &ctx)) return FALSE; if (ctx.level != 0) { i_error("Missing '}'"); return FALSE; } /* If server sections were defined, skip the root */ if (ctx.root->next != NULL) ctx.root = ctx.root->next; prev = NULL; for (server = ctx.root; server != NULL; server = server->next) { if (server->imap->protocols == NULL || server->pop3->protocols == NULL) { i_error("No protocols given in configuration file"); return FALSE; } if (!settings_is_active(server->imap)) server->imap = NULL; else { if (!nochecks && !settings_verify(server->imap)) return FALSE; server->defaults = server->imap; } if (!settings_is_active(server->pop3)) server->pop3 = NULL; else { if (!nochecks && !settings_verify(server->pop3)) return FALSE; if (server->defaults == NULL) server->defaults = server->pop3; } if (server->defaults == NULL) { if (prev == NULL) ctx.root = server->next; else prev->next = server->next; } else { auth = server->auths; if (auth == NULL) { i_error("Missing auth section for server %s", server->name); return FALSE; } if (!nochecks) { for (; auth != NULL; auth = auth->next) { if (!auth_settings_verify(auth)) return FALSE; } ns = server->namespaces; for (; ns != NULL; ns = ns->next) { if (!namespace_settings_verify(ns)) return FALSE; } } prev = server; } } /* settings ok, swap them */ temp = settings_pool; settings_pool = settings2_pool; settings2_pool = temp; settings_root = ctx.root; return TRUE; } void master_settings_init(void) { settings_pool = pool_alloconly_create("settings", 2048); settings2_pool = pool_alloconly_create("settings2", 2048); } void master_settings_deinit(void) { pool_unref(settings_pool); pool_unref(settings2_pool); }