Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1055:a72bba3f8a55 HEAD
Rewrote setting handling. Changed some existing settings also since POP3
support required changes anyway. POP3 seems to be really working now :)
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 30 Jan 2003 19:59:31 +0200 |
parents | cd1ac4101adf |
children | a9b499b2611e |
files | dovecot-example.conf src/imap/main.c src/login-common/main.c src/master/.cvsignore src/master/Makefile.am src/master/auth-process.c src/master/common.h src/master/imap-process.c src/master/imap-process.h src/master/login-process.c src/master/mail-process.c src/master/mail-process.h src/master/main.c src/master/master-login-interface.h src/master/settings.c src/master/settings.h src/master/ssl-init.c |
diffstat | 17 files changed, 1093 insertions(+), 846 deletions(-) [+] |
line wrap: on
line diff
--- a/dovecot-example.conf Thu Jan 30 19:56:19 2003 +0200 +++ b/dovecot-example.conf Thu Jan 30 19:59:31 2003 +0200 @@ -9,32 +9,32 @@ # Base directory where to store runtime data. #base_dir = /var/run/dovecot/ -# Port to listen in for IMAP connections. This port is used for TLS -# connections as well. Setting it to 0 disables it. -#imap_port = 143 +# Protocols we want to be serving: +# imap imaps pop3 pop3s +#protocols = imap imaps -# Port to listen in for SSL IMAP connections. Setting it to 0 disables it. -#imaps_port = 993 - -# IP or host address where to listen in for IMAP connections. It's not +# IP or host address where to listen in for connections. It's not currently # possible to specify multiple addresses. "*" listens in all IPv4 interfaces. -# "::" listens in all IPv6 interfaces, but may also listen in all IPv4 -# interfaces depending on the operating system. +# "[::]" listens in all IPv6 interfaces, but may also listen in all IPv4 +# interfaces depending on the operating system. You can specify ports with +# "host:port". #imap_listen = * +#pop3_listen = * -# IP or host address where to listen in for SSL IMAP connections. Defaults -# to imap_listen if not specified. +# IP or host address where to listen in for SSL connections. Defaults +# to above non-SSL equilevants if not specified. #imaps_listen = +#pop3s_listen = -# Disable SSL support. +# Disable SSL/TLS support. #ssl_disable = no # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before # dropping root privileges, so keep the key file unreadable by anyone but # root. Included doc/mkcert.sh can be used to easily generate self-signed # certificate, just make sure to update the domains in dovecot-openssl.cnf -#ssl_cert_file = /etc/ssl/certs/imapd.pem -#ssl_key_file = /etc/ssl/private/imapd.pem +#ssl_cert_file = /etc/ssl/certs/dovecot.pem +#ssl_key_file = /etc/ssl/private/dovecot.pem # SSL parameter file. Master process generates this file for login processes. # It contains Diffie Hellman and RSA parameters. @@ -60,37 +60,44 @@ #log_timestamp = %b %d %H:%M:%S ## -## Login process +## Login processes ## +# Directory where authentication process places authentication UNIX sockets +# which login needs to be able to connect to. The sockets are created when +# running as root, so you don't have to worry about permissions. +#login_dir = /var/run/dovecot/login + +# chroot login process to the login_dir. Only reason not to do this is if you +# wish to run the whole Dovecot without roots. +#login_chroot = yes + + +## +## IMAP login process +## + +login = imap + # Executable location. #login_executable = /usr/libexec/dovecot/imap-login -# User to use for imap-login process. The user must belong to a group -# where only it has access, it's used to control access for authentication -# process named sockets. -#login_user = imapd +# User to use for the login process. The user must belong to a group where +# only it has access, it's used to control access for authentication process +# named sockets. +#login_user = dovecot # Set max. process size in megabytes. If you don't use # login_process_per_connection you might need to grow this. #login_process_size = 16 -# Directory where imap-auth places authentication UNIX sockets which login -# needs to be able to connect to. The sockets are created when running as -# root, so you don't need to give imap-auth any access for it. -#login_dir = /var/run/dovecot/login - -# chroot imap-login process to the login_dir. Only reason not to do this -# is if you wish to run the whole imapd without roots. -#login_chroot = yes - # Should each login be processed in it's own process (yes), or should one # login process be allowed to process multiple connections (no)? Yes is more # secure, espcially with SSL/TLS enabled. No is faster since there's no need # to create processes all the time. #login_process_per_connection = yes -# Number of imap-login processes to create. If login_process_per_user is +# Number of login processes to create. If login_process_per_user is # yes, this is the number of extra processes waiting for users to log in. #login_processes_count = 3 @@ -109,27 +116,32 @@ #max_logging_users = 256 ## -## IMAP process +## POP3 login process ## -# Executable location -#imap_executable = /usr/libexec/dovecot/imap +# Settings default to same as above, so you don't have to set anything +# unless you want to override them. + +login = pop3 + +# Exception to above rule being the executable location. +#login_executable = /usr/libexec/dovecot/pop3-login -# Set max. process size in megabytes. Most of the memory goes to mmap()ing -# files, so it shouldn't harm much even if this limit is set pretty high. -#imap_process_size = 256 +## +## Mail processes +## -# Maximum number of running imap processes. When this limit is reached, +# Maximum number of running mail processes. When this limit is reached, # new users aren't allowed to log in. -#max_imap_processes = 1024 +#max_mail_processes = 1024 # Show more verbose process titles (in ps). Currently shows user name and # IP address. Useful for seeing who are actually using the IMAP processes # (eg. shared mailboxes or if same uid is used for multiple accounts). #verbose_proctitle = no -# Valid UID/GID ranges for imap users, defaults to 500 and above. -# Note that denying root logins is hardcoded to imap-master binary and +# Valid UID/GID ranges for users, defaults to 500 and above. +# Note that denying root logins is hardcoded to dovecot-master binary and # can't be done even if first_valid_uid is set to 0. #first_valid_uid = 500 #last_valid_uid = 0 @@ -137,7 +149,7 @@ #first_valid_gid = 1 #last_valid_gid = 0 -# ':' separated list of directories under which chrooting is allowed for imap +# ':' separated list of directories under which chrooting is allowed for mail # processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too). # This setting doesn't affect login_chroot or auth_chroot variables. # WARNING: Never add directories here which local users can modify, that @@ -257,6 +269,28 @@ #umask = 0077 ## +## IMAP process +## + +# Executable location +#imap_executable = /usr/libexec/dovecot/imap + +# Set max. process size in megabytes. Most of the memory goes to mmap()ing +# files, so it shouldn't harm much even if this limit is set pretty high. +#imap_process_size = 256 + +## +## POP3 process +## + +# Executable location +#pop3_executable = /usr/libexec/dovecot/pop3 + +# Set max. process size in megabytes. Most of the memory goes to mmap()ing +# files, so it shouldn't harm much even if this limit is set pretty high. +#pop3_process_size = 256 + +## ## Authentication processes ## @@ -302,7 +336,7 @@ auth_passdb = pam # Executable location -#auth_executable = /usr/libexec/dovecot/imap-auth +#auth_executable = /usr/libexec/dovecot/dovecot-auth # Set max. process size in megabytes. #auth_process_size = 256
--- a/src/imap/main.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/imap/main.c Thu Jan 30 19:59:31 2003 +0200 @@ -36,17 +36,17 @@ } i_snprintf(log_prefix, sizeof(log_prefix), "imap(%s)", user); - if (getenv("IMAP_USE_SYSLOG") != NULL) + if (getenv("USE_SYSLOG") != NULL) i_set_failure_syslog(log_prefix, LOG_NDELAY, LOG_MAIL); else { /* log to file or stderr */ - i_set_failure_file(getenv("IMAP_LOGFILE"), log_prefix); + i_set_failure_file(getenv("LOGFILE"), log_prefix); } - if (getenv("IMAP_INFOLOGFILE") != NULL) - i_set_info_file(getenv("IMAP_INFOLOGFILE")); + if (getenv("INFOLOGFILE") != NULL) + i_set_info_file(getenv("INFOLOGFILE")); - i_set_failure_timestamp_format(getenv("IMAP_LOGSTAMP")); + i_set_failure_timestamp_format(getenv("LOGSTAMP")); } static void drop_privileges(void)
--- a/src/login-common/main.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/login-common/main.c Thu Jan 30 19:59:31 2003 +0200 @@ -20,7 +20,7 @@ unsigned int login_process_uid; static struct ioloop *ioloop; -static struct io *io_listen, *io_listen_ssl; +static struct io *io_listen, *io_ssl_listen; static int main_refcount; static int closing_down; @@ -48,18 +48,18 @@ if (io_listen != NULL) { if (close(LOGIN_LISTEN_FD) < 0) - i_fatal("can't close() IMAP listen handle"); + i_fatal("close(listen) failed: %m"); io_remove(io_listen); io_listen = NULL; } - if (io_listen_ssl != NULL) { + if (io_ssl_listen != NULL) { if (close(LOGIN_SSL_LISTEN_FD) < 0) - i_fatal("can't close() IMAPS listen handle"); + i_fatal("close(ssl_listen) failed: %m"); - io_remove(io_listen_ssl); - io_listen_ssl = NULL; + io_remove(io_ssl_listen); + io_ssl_listen = NULL; } closing_down = TRUE; @@ -114,7 +114,7 @@ static void open_logfile(const char *name) { - if (getenv("IMAP_USE_SYSLOG") != NULL) + if (getenv("USE_SYSLOG") != NULL) i_set_failure_syslog(name, LOG_NDELAY, LOG_MAIL); else { /* log to file or stderr */ @@ -167,24 +167,22 @@ auth_connection_init(); clients_init(); - io_listen = io_listen_ssl = NULL; + io_listen = io_ssl_listen = NULL; if (net_getsockname(LOGIN_LISTEN_FD, NULL, NULL) == 0) { - /* we're listening for imap */ io_listen = io_add(LOGIN_LISTEN_FD, IO_READ, login_accept, NULL); } if (net_getsockname(LOGIN_SSL_LISTEN_FD, NULL, NULL) == 0) { - /* we're listening for imaps */ if (!ssl_initialized) { /* this shouldn't happen, master should have - disabled the imaps socket.. */ + disabled the ssl socket.. */ i_fatal("BUG: SSL initialization parameters not given " "while they should have been"); } - io_listen_ssl = io_add(LOGIN_SSL_LISTEN_FD, IO_READ, + io_ssl_listen = io_add(LOGIN_SSL_LISTEN_FD, IO_READ, login_accept_ssl, NULL); } @@ -198,7 +196,7 @@ i_warning("Killed with signal %d", lib_signal_kill); if (io_listen != NULL) io_remove(io_listen); - if (io_listen_ssl != NULL) io_remove(io_listen_ssl); + if (io_ssl_listen != NULL) io_remove(io_ssl_listen); clients_deinit(); master_deinit();
--- a/src/master/.cvsignore Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/.cvsignore Thu Jan 30 19:59:31 2003 +0200 @@ -6,4 +6,4 @@ Makefile Makefile.in so_locations -imap-master +dovecot
--- a/src/master/Makefile.am Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/Makefile.am Thu Jan 30 19:59:31 2003 +0200 @@ -1,6 +1,6 @@ pkglibexecdir = $(libexecdir)/dovecot -sbin_PROGRAMS = imap-master +sbin_PROGRAMS = dovecot INCLUDES = \ -I$(top_srcdir)/src/lib \ @@ -9,14 +9,14 @@ -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \ -DSSLDIR=\""$(ssldir)\"" -imap_master_LDADD = \ +dovecot_LDADD = \ ../lib/liblib.a \ $(SSL_LIBS) -imap_master_SOURCES = \ +dovecot_SOURCES = \ auth-process.c \ - imap-process.c \ login-process.c \ + mail-process.c \ main.c \ settings.c \ ssl-init.c \ @@ -26,8 +26,8 @@ noinst_HEADERS = \ auth-process.h \ common.h \ - imap-process.h \ login-process.h \ + mail-process.h \ master-login-interface.h \ settings.h \ ssl-init.h
--- a/src/master/auth-process.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/auth-process.c Thu Jan 30 19:59:31 2003 +0200 @@ -222,7 +222,7 @@ } } - (void)unlink(t_strconcat(set_login_dir, "/", p->name, NULL)); + (void)unlink(t_strconcat(set->login_dir, "/", p->name, NULL)); hash_foreach(p->requests, request_hash_destroy, NULL); hash_destroy(p->requests); @@ -236,7 +236,7 @@ i_free(p); } -static pid_t create_auth_process(struct auth_config *config) +static pid_t create_auth_process(struct auth_settings *auth_set) { static char *argv[] = { NULL, NULL }; const char *path; @@ -244,8 +244,8 @@ pid_t pid; int fd[2], listen_fd, i; - if ((pwd = getpwnam(config->user)) == NULL) - i_fatal("Auth user doesn't exist: %s", config->user); + if ((pwd = getpwnam(auth_set->user)) == NULL) + i_fatal("Auth user doesn't exist: %s", auth_set->user); /* create communication to process with a socket pair */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { @@ -264,13 +264,13 @@ if (pid != 0) { /* master */ fd_close_on_exec(fd[0], TRUE); - auth_process_new(pid, fd[0], config->name); + auth_process_new(pid, fd[0], auth_set->name); (void)close(fd[1]); return pid; } - /* create socket for listening auth requests from imap-login */ - path = t_strconcat(set_login_dir, "/", config->name, NULL); + /* create socket for listening auth requests from login */ + path = t_strconcat(set->login_dir, "/", auth_set->name, NULL); (void)unlink(path); (void)umask(0117); /* we want 0660 mode for the socket */ @@ -281,9 +281,9 @@ i_assert(listen_fd > 2); /* set correct permissions */ - if (chown(path, geteuid(), set_login_gid) < 0) { + if (chown(path, geteuid(), set->login_gid) < 0) { i_fatal("login: chown(%s, %s, %s) failed: %m", - path, dec2str(set_login_uid), dec2str(set_login_gid)); + path, dec2str(geteuid()), dec2str(set->login_gid)); } /* move master communication handle to 0 */ @@ -315,34 +315,35 @@ /* setup access environment - needs to be done after clean_child_process() since it clears environment */ - restrict_access_set_env(config->user, pwd->pw_uid, pwd->pw_gid, - config->chroot); + restrict_access_set_env(auth_set->user, pwd->pw_uid, pwd->pw_gid, + auth_set->chroot); /* set other environment */ env_put(t_strconcat("AUTH_PROCESS=", dec2str(getpid()), NULL)); - env_put(t_strconcat("MECHANISMS=", config->mechanisms, NULL)); - env_put(t_strconcat("REALMS=", config->realms, NULL)); - env_put(t_strconcat("USERDB=", config->userdb, NULL)); - env_put(t_strconcat("USERDB_ARGS=", config->userdb_args, NULL)); - env_put(t_strconcat("PASSDB=", config->passdb, NULL)); - env_put(t_strconcat("PASSDB_ARGS=", config->passdb_args, NULL)); + env_put(t_strconcat("MECHANISMS=", auth_set->mechanisms, NULL)); + env_put(t_strconcat("REALMS=", auth_set->realms, NULL)); + env_put(t_strconcat("USERDB=", auth_set->userdb, NULL)); + env_put(t_strconcat("PASSDB=", auth_set->passdb, NULL)); - if (config->use_cyrus_sasl) + if (auth_set->use_cyrus_sasl) env_put("USE_CYRUS_SASL=1"); - if (config->verbose) + if (auth_set->verbose) env_put("VERBOSE=1"); - restrict_process_size(config->process_size); + restrict_process_size(auth_set->process_size); /* make sure we don't leak syslog fd, but do it last so that any errors above will be logged */ closelog(); /* hide the path, it's ugly */ - argv[0] = strrchr(config->executable, '/'); - if (argv[0] == NULL) argv[0] = config->executable; else argv[0]++; + argv[0] = strrchr(auth_set->executable, '/'); + if (argv[0] == NULL) + argv[0] = i_strdup(auth_set->executable); + else + argv[0]++; - execv(config->executable, (char **) argv); + execv(auth_set->executable, argv); i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", argv[0]); return -1; @@ -387,14 +388,14 @@ static void auth_processes_start_missing(void *context __attr_unused__) { - struct auth_config *config; + struct auth_settings *auth_set; unsigned int count; - config = auth_processes_config; - for (; config != NULL; config = config->next) { - count = auth_process_get_count(config->name); - for (; count < config->count; count++) - (void)create_auth_process(config); + auth_set = set->auths; + for (; auth_set != NULL; auth_set = auth_set->next) { + count = auth_process_get_count(auth_set->name); + for (; count < auth_set->count; count++) + (void)create_auth_process(auth_set); } }
--- a/src/master/common.h Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/common.h Thu Jan 30 19:59:31 2003 +0200 @@ -13,15 +13,24 @@ PROCESS_TYPE_UNKNOWN, PROCESS_TYPE_AUTH, PROCESS_TYPE_LOGIN, - PROCESS_TYPE_IMAP, + PROCESS_TYPE_MAIL, PROCESS_TYPE_SSL_PARAM, PROCESS_TYPE_MAX }; +enum { + FD_IMAP, + FD_IMAPS, + FD_POP3, + FD_POP3S, + + FD_MAX +}; + extern struct ioloop *ioloop; extern struct hash_table *pids; -extern int null_fd, imap_fd, imaps_fd; +extern int null_fd, mail_fd[FD_MAX]; /* processes */ #define PID_GET_PROCESS_TYPE(pid) \
--- a/src/master/imap-process.c Thu Jan 30 19:56:19 2003 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* Copyright (C) 2002 Timo Sirainen */ - -#include "common.h" -#include "fd-close-on-exec.h" -#include "env-util.h" -#include "str.h" -#include "network.h" -#include "restrict-access.h" -#include "restrict-process-size.h" -#include "var-expand.h" -#include "imap-process.h" - -#include <stdlib.h> -#include <unistd.h> -#include <grp.h> -#include <syslog.h> -#include <sys/stat.h> - -static unsigned int imap_process_count = 0; - -static int validate_uid_gid(uid_t uid, gid_t gid) -{ - if (uid == 0) { - i_error("imap process isn't allowed for root"); - return FALSE; - } - - if (uid != 0 && gid == 0) { - i_error("imap process isn't allowed to be in group 0"); - return FALSE; - } - - if (uid < (uid_t)set_first_valid_uid || - (set_last_valid_uid != 0 && uid > (uid_t)set_last_valid_uid)) { - i_error("imap process isn't allowed to use UID %s", - dec2str(uid)); - return FALSE; - } - - if (gid < (gid_t)set_first_valid_gid || - (set_last_valid_gid != 0 && gid > (gid_t)set_last_valid_gid)) { - i_error("imap process isn't allowed to use " - "GID %s (UID is %s)", dec2str(gid), dec2str(uid)); - return FALSE; - } - - return TRUE; -} - -static int validate_chroot(const char *dir) -{ - const char *const *chroot_dirs; - - if (*dir == '\0') - return FALSE; - - if (set_valid_chroot_dirs == NULL) - return FALSE; - - chroot_dirs = t_strsplit(set_valid_chroot_dirs, ":"); - while (*chroot_dirs != NULL) { - if (**chroot_dirs != '\0' && - strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0) - return TRUE; - chroot_dirs++; - } - - return FALSE; -} - -static const char *expand_mail_env(const char *env, const char *user, - const char *home) -{ - string_t *str; - const char *p; - - str = t_str_new(256); - - /* it's either type:data or just data */ - p = strchr(env, ':'); - if (p != NULL) { - while (env != p) { - str_append_c(str, *env); - env++; - } - - str_append_c(str, *env++); - } - - if (env[0] == '~' && env[1] == '/') { - /* expand home */ - str_append(str, home); - env++; - } - - /* expand %vars */ - var_expand(str, env, user, home); - return str_c(str); -} - -int create_imap_process(int socket, struct ip_addr *ip, - struct auth_master_reply *reply, const char *data) -{ - static char *argv[] = { NULL, NULL, NULL }; - const char *host, *mail; - char title[1024]; - pid_t pid; - int i, err; - - if (imap_process_count == set_max_imap_processes) { - i_error("Maximum number of imap processes exceeded"); - return FALSE; - } - - if (!validate_uid_gid(reply->uid, reply->gid)) - return FALSE; - - if (reply->chroot && !validate_chroot(data + reply->home_idx)) - return FALSE; - - pid = fork(); - if (pid < 0) { - i_error("fork() failed: %m"); - return FALSE; - } - - if (pid != 0) { - /* master */ - imap_process_count++; - PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_IMAP); - return TRUE; - } - - clean_child_process(); - - /* move the imap socket into stdin, stdout and stderr fds */ - fd_close_on_exec(socket, FALSE); - for (i = 0; i < 3; i++) { - if (dup2(socket, i) < 0) - i_fatal("imap: dup2(%d) failed: %m", i); - } - - if (close(socket) < 0) - i_error("imap: close(imap client) failed: %m"); - - /* setup environment - set the most important environment first - (paranoia about filling up environment without noticing) */ - restrict_access_set_env(data + reply->system_user_idx, - reply->uid, reply->gid, - reply->chroot ? data + reply->home_idx : NULL); - restrict_process_size(set_imap_process_size); - - env_put("LOGGED_IN=1"); - env_put(t_strconcat("HOME=", data + reply->home_idx, NULL)); - env_put(t_strconcat("MAIL_CACHE_FIELDS=", set_mail_cache_fields, NULL)); - env_put(t_strconcat("MAIL_NEVER_CACHE_FIELDS=", - set_mail_never_cache_fields, NULL)); - env_put(t_strdup_printf("MAILBOX_CHECK_INTERVAL=%u", - set_mailbox_check_interval)); - - if (set_mail_save_crlf) - env_put("MAIL_SAVE_CRLF=1"); - if (set_mail_read_mmaped) - env_put("MAIL_READ_MMAPED=1"); - if (set_maildir_copy_with_hardlinks) - env_put("MAILDIR_COPY_WITH_HARDLINKS=1"); - if (set_maildir_check_content_changes) - env_put("MAILDIR_CHECK_CONTENT_CHANGES=1"); - if (set_overwrite_incompatible_index) - env_put("OVERWRITE_INCOMPATIBLE_INDEX=1"); - if (umask(set_umask) != set_umask) - i_fatal("Invalid umask: %o", set_umask); - - env_put(t_strconcat("MBOX_LOCKS=", set_mbox_locks, NULL)); - env_put(t_strdup_printf("MBOX_LOCK_TIMEOUT=%u", set_mbox_lock_timeout)); - env_put(t_strdup_printf("MBOX_DOTLOCK_CHANGE_TIMEOUT=%u", - set_mbox_dotlock_change_timeout)); - if (set_mbox_read_dotlock) - env_put("MBOX_READ_DOTLOCK=1"); - - /* user given environment - may be malicious. virtual_user comes from - auth process, but don't trust that too much either. Some auth - mechanism might allow leaving extra data there. */ - mail = data + reply->mail_idx; - if (*mail == '\0' && set_default_mail_env != NULL) { - mail = expand_mail_env(set_default_mail_env, - data + reply->virtual_user_idx, - data + reply->home_idx); - } - - env_put(t_strconcat("MAIL=", mail, NULL)); - env_put(t_strconcat("USER=", data + reply->virtual_user_idx, NULL)); - - if (set_verbose_proctitle) { - host = net_ip2host(ip); - if (host == NULL) - host = "??"; - - i_snprintf(title, sizeof(title), "[%s %s]", - data + reply->virtual_user_idx, host); - argv[1] = title; - } - - /* make sure we don't leak syslog fd, but do it last so that - any errors above will be logged */ - closelog(); - - /* hide the path, it's ugly */ - argv[0] = strrchr(set_imap_executable, '/'); - if (argv[0] == NULL) argv[0] = set_imap_executable; else argv[0]++; - - execv(set_imap_executable, argv); - err = errno; - - for (i = 0; i < 3; i++) - (void)close(i); - - i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", set_imap_executable); - - /* not reached */ - return FALSE; -} - -void imap_process_destroyed(pid_t pid __attr_unused__) -{ - imap_process_count--; -}
--- a/src/master/imap-process.h Thu Jan 30 19:56:19 2003 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#ifndef __IMAP_PROCESS_H -#define __IMAP_PROCESS_H - -struct auth_master_reply; - -int create_imap_process(int socket, struct ip_addr *ip, - struct auth_master_reply *reply, const char *data); -void imap_process_destroyed(pid_t pid); - -#endif
--- a/src/master/login-process.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/login-process.c Thu Jan 30 19:59:31 2003 +0200 @@ -11,13 +11,31 @@ #include "restrict-process-size.h" #include "login-process.h" #include "auth-process.h" -#include "imap-process.h" +#include "mail-process.h" #include "master-login-interface.h" #include <unistd.h> #include <syslog.h> +struct login_group { + struct login_group *next; + + struct login_settings *set; + + unsigned int processes; + unsigned int listening_processes; + unsigned int wanted_processes_count; + + struct login_process *oldest_nonlisten_process; + struct login_process *newest_nonlisten_process; + + const char *executable; + unsigned int process_size; + int *listen_fd, *ssl_listen_fd; +}; + struct login_process { + struct login_group *group; struct login_process *prev_nonlisten, *next_nonlisten; int refcount; @@ -44,14 +62,40 @@ static struct timeout *to; static struct hash_table *processes; -static struct login_process *oldest_nonlisten_process; -static struct login_process *newest_nonlisten_process; -static unsigned int listening_processes; -static unsigned int wanted_processes_count; +static struct login_group *login_groups; static void login_process_destroy(struct login_process *p); static void login_process_unref(struct login_process *p); +static void login_group_create(struct login_settings *login_set) +{ + struct login_group *group; + + group = i_new(struct login_group, 1); + group->set = login_set; + + if (strcmp(login_set->name, "imap") == 0) { + group->executable = set->imap_executable; + group->process_size = set->imap_process_size; + group->listen_fd = &mail_fd[FD_IMAP]; + group->ssl_listen_fd = &mail_fd[FD_IMAPS]; + } else if (strcmp(login_set->name, "pop3") == 0) { + group->executable = set->pop3_executable; + group->process_size = set->pop3_process_size; + group->listen_fd = &mail_fd[FD_POP3]; + group->ssl_listen_fd = &mail_fd[FD_POP3S]; + } else + i_panic("Unknown login group name '%s'", login_set->name); + + group->next = login_groups; + login_groups = group; +} + +static void login_group_destroy(struct login_group *group) +{ + i_free(group); +} + void auth_master_callback(struct auth_master_reply *reply, const unsigned char *data, void *context) { @@ -61,9 +105,13 @@ if (reply == NULL || !reply->success) master_reply.success = FALSE; else { + struct login_group *group = request->process->group; + master_reply.success = - create_imap_process(request->fd, &request->ip, reply, - (const char *) data); + create_mail_process(request->fd, &request->ip, + group->executable, + group->process_size, + reply, (const char *) data); } /* reply to login */ @@ -74,7 +122,7 @@ login_process_destroy(request->process); if (close(request->fd) < 0) - i_error("close(imap client) failed: %m"); + i_error("close(mail client) failed: %m"); login_process_unref(request->process); i_free(request); } @@ -88,16 +136,16 @@ } p->listening = FALSE; - listening_processes--; + p->group->listening_processes--; - p->prev_nonlisten = newest_nonlisten_process; + p->prev_nonlisten = p->group->newest_nonlisten_process; - if (newest_nonlisten_process != NULL) - newest_nonlisten_process->next_nonlisten = p; - newest_nonlisten_process = p; + if (p->group->newest_nonlisten_process != NULL) + p->group->newest_nonlisten_process->next_nonlisten = p; + p->group->newest_nonlisten_process = p; - if (oldest_nonlisten_process == NULL) - oldest_nonlisten_process = p; + if (p->group->oldest_nonlisten_process == NULL) + p->group->oldest_nonlisten_process = p; } static void login_process_input(void *context) @@ -121,7 +169,7 @@ if (client_fd != -1) { if (close(client_fd) < 0) - i_error("close(imap client) failed: %m"); + i_error("close(mail client) failed: %m"); } login_process_destroy(p); @@ -162,13 +210,15 @@ } } -static struct login_process *login_process_new(pid_t pid, int fd) +static struct login_process * +login_process_new(struct login_group *group, pid_t pid, int fd) { struct login_process *p; PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN); p = i_new(struct login_process, 1); + p->group = group; p->refcount = 1; p->pid = pid; p->fd = fd; @@ -179,19 +229,20 @@ IO_PRIORITY_DEFAULT, FALSE); hash_insert(processes, POINTER_CAST(pid), p); - listening_processes++; + p->group->processes++; + p->group->listening_processes++; return p; } static void login_process_remove_from_lists(struct login_process *p) { - if (p == oldest_nonlisten_process) - oldest_nonlisten_process = p->next_nonlisten; + if (p == p->group->oldest_nonlisten_process) + p->group->oldest_nonlisten_process = p->next_nonlisten; else p->prev_nonlisten->next_nonlisten = p->next_nonlisten; - if (p == newest_nonlisten_process) - newest_nonlisten_process = p->prev_nonlisten; + if (p == p->group->newest_nonlisten_process) + p->group->newest_nonlisten_process = p->prev_nonlisten; else p->next_nonlisten->prev_nonlisten = p->prev_nonlisten; @@ -209,7 +260,7 @@ io_loop_stop(ioloop); } if (p->listening) - listening_processes--; + p->group->listening_processes--; o_stream_close(p->output); io_remove(p->io); @@ -219,6 +270,7 @@ if (!p->listening) login_process_remove_from_lists(p); + p->group->processes--; hash_remove(processes, POINTER_CAST(p->pid)); login_process_unref(p); @@ -233,19 +285,20 @@ i_free(p); } -static pid_t create_login_process(void) +static pid_t create_login_process(struct login_group *group) { - static char *argv[] = { NULL, NULL }; + static const char *argv[] = { NULL, NULL }; pid_t pid; int fd[2]; - if (set_login_process_per_connection && - hash_size(processes)-listening_processes >= set_max_logging_users) { - if (oldest_nonlisten_process != NULL) - login_process_destroy(oldest_nonlisten_process); + if (group->set->process_per_connection && + group->processes - group->listening_processes >= + group->set->max_logging_users) { + if (group->oldest_nonlisten_process != NULL) + login_process_destroy(group->oldest_nonlisten_process); } - if (set_login_uid == 0) + if (group->set->uid == 0) i_fatal("Login process must not run as root"); /* create communication to process with a socket pair */ @@ -265,7 +318,7 @@ if (pid != 0) { /* master */ fd_close_on_exec(fd[0], TRUE); - login_process_new(pid, fd[0]); + login_process_new(group, pid, fd[0]); (void)close(fd[1]); return pid; } @@ -276,21 +329,21 @@ fd_close_on_exec(LOGIN_MASTER_SOCKET_FD, FALSE); /* move the listen handle */ - if (dup2(imap_fd, LOGIN_IMAP_LISTEN_FD) < 0) - i_fatal("login: dup2(imap) failed: %m"); - fd_close_on_exec(LOGIN_IMAP_LISTEN_FD, FALSE); + if (dup2(*group->listen_fd, LOGIN_LISTEN_FD) < 0) + i_fatal("login: dup2(listen_fd) failed: %m"); + fd_close_on_exec(LOGIN_LISTEN_FD, FALSE); /* move the SSL listen handle */ - if (!set_ssl_disable) { - if (dup2(imaps_fd, LOGIN_IMAPS_LISTEN_FD) < 0) - i_fatal("login: dup2(imaps) failed: %m"); + if (!set->ssl_disable) { + if (dup2(*group->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0) + i_fatal("login: dup2(ssl_listen_fd) failed: %m"); } else { - if (dup2(null_fd, LOGIN_IMAPS_LISTEN_FD) < 0) - i_fatal("login: dup2(imaps) failed: %m"); + if (dup2(null_fd, LOGIN_SSL_LISTEN_FD) < 0) + i_fatal("login: dup2(ssl_listen_fd) failed: %m"); } - fd_close_on_exec(LOGIN_IMAPS_LISTEN_FD, FALSE); + fd_close_on_exec(LOGIN_SSL_LISTEN_FD, FALSE); - /* imap_fd and imaps_fd are closed by clean_child_process() */ + /* listen_fds are closed by clean_child_process() */ (void)close(fd[0]); (void)close(fd[1]); @@ -299,58 +352,64 @@ /* setup access environment - needs to be done after clean_child_process() since it clears environment */ - restrict_access_set_env(set_login_user, set_login_uid, set_login_gid, - set_login_chroot ? set_login_dir : NULL); + restrict_access_set_env(group->set->user, + group->set->uid, set->login_gid, + set->login_chroot ? set->login_dir : NULL); - if (!set_login_chroot) { + if (!set->login_chroot) { /* no chrooting, but still change to the directory */ - if (chdir(set_login_dir) < 0) - i_fatal("chdir(%s) failed: %m", set_login_dir); + if (chdir(set->login_dir) < 0) + i_fatal("chdir(%s) failed: %m", set->login_dir); } - if (!set_ssl_disable) { - env_put(t_strconcat("SSL_CERT_FILE=", set_ssl_cert_file, NULL)); - env_put(t_strconcat("SSL_KEY_FILE=", set_ssl_key_file, NULL)); + if (!set->ssl_disable) { + env_put(t_strconcat("SSL_CERT_FILE=", + set->ssl_cert_file, NULL)); + env_put(t_strconcat("SSL_KEY_FILE=", set->ssl_key_file, NULL)); env_put(t_strconcat("SSL_PARAM_FILE=", - set_ssl_parameters_file, NULL)); + set->ssl_parameters_file, NULL)); } - if (set_disable_plaintext_auth) + if (set->disable_plaintext_auth) env_put("DISABLE_PLAINTEXT_AUTH=1"); - if (set_verbose_proctitle) + if (set->verbose_proctitle) env_put("VERBOSE_PROCTITLE=1"); - if (set_login_process_per_connection) { + if (group->set->process_per_connection) { env_put("PROCESS_PER_CONNECTION=1"); env_put("MAX_LOGGING_USERS=1"); } else { env_put(t_strdup_printf("MAX_LOGGING_USERS=%u", - set_max_logging_users)); + group->set->max_logging_users)); } env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(getpid()))); - restrict_process_size(set_login_process_size); + restrict_process_size(group->set->process_size); /* make sure we don't leak syslog fd, but do it last so that any errors above will be logged */ closelog(); /* hide the path, it's ugly */ - argv[0] = strrchr(set_login_executable, '/'); - if (argv[0] == NULL) argv[0] = set_login_executable; else argv[0]++; + argv[0] = strrchr(group->set->executable, '/'); + if (argv[0] == NULL) argv[0] = group->set->executable; else argv[0]++; - execv(set_login_executable, (char **) argv); + execv(group->set->executable, (char **) argv); i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", argv[0]); return -1; } -void login_process_abormal_exit(pid_t pid __attr_unused__) +void login_process_abormal_exit(pid_t pid) { + struct login_process *p; + /* don't start raising the process count if they're dying all the time */ - wanted_processes_count = 0; + p = hash_lookup(processes, POINTER_CAST(pid)); + if (p != NULL) + p->group->wanted_processes_count = 0; } static void login_hash_destroy(void *key __attr_unused__, void *value, @@ -363,47 +422,64 @@ { hash_foreach(processes, login_hash_destroy, NULL); - /* don't double their amount when restarting */ - wanted_processes_count = 0; + while (login_groups != NULL) { + struct login_group *group = login_groups; + + login_groups = group->next; + login_group_destroy(group); + } +} + +static void login_group_start_missings(struct login_group *group) +{ + if (!group->set->process_per_connection) { + /* create max. one process every second, that way if it keeps + dying all the time we don't eat all cpu with fork()ing. */ + if (group->listening_processes < group->set->processes_count) + (void)create_login_process(group); + return; + } + + /* we want to respond fast when multiple clients are connecting + at once, but we also want to prevent fork-bombing. use the + same method as apache: check once a second if we need new + processes. if yes and we've used all the existing processes, + double their amount (unless we've hit the high limit). + Then for each second that didn't use all existing processes, + drop the max. process count by one. */ + if (group->wanted_processes_count < group->set->processes_count) + group->wanted_processes_count = group->set->processes_count; + else if (group->listening_processes == 0) + group->wanted_processes_count *= 2; + else if (group->wanted_processes_count > group->set->processes_count) + group->wanted_processes_count--; + + if (group->wanted_processes_count > group->set->max_processes_count) + group->wanted_processes_count = group->set->max_processes_count; + + while (group->listening_processes < group->wanted_processes_count) + (void)create_login_process(group); } static void login_processes_start_missing(void *context __attr_unused__) { - if (!set_login_process_per_connection) { - /* create max. one process every second, that way if it keeps - dying all the time we don't eat all cpu with fork()ing. */ - if (listening_processes < set_login_processes_count) - (void)create_login_process(); - } else { - /* we want to respond fast when multiple clients are connecting - at once, but we also want to prevent fork-bombing. use the - same method as apache: check once a second if we need new - processes. if yes and we've used all the existing processes, - double their amount (unless we've hit the high limit). - Then for each second that didn't use all existing processes, - drop the max. process count by one. */ - if (wanted_processes_count < set_login_processes_count) - wanted_processes_count = set_login_processes_count; - else if (listening_processes == 0) - wanted_processes_count *= 2; - else if (wanted_processes_count > set_login_processes_count) - wanted_processes_count--; + struct login_group *group; + struct login_settings *login; - if (wanted_processes_count > set_login_max_processes_count) - wanted_processes_count = set_login_max_processes_count; + if (login_groups == NULL) { + for (login = set->logins; login != NULL; login = login->next) + login_group_create(login); + } - while (listening_processes < wanted_processes_count) - (void)create_login_process(); - } + for (group = login_groups; group != NULL; group = group->next) + login_group_start_missings(group); } void login_processes_init(void) { auth_id_counter = 0; - listening_processes = 0; - wanted_processes_count = 0; - oldest_nonlisten_process = newest_nonlisten_process = NULL; + login_groups = NULL; processes = hash_create(default_pool, default_pool, 128, NULL, NULL); to = timeout_add(1000, login_processes_start_missing, NULL);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/master/mail-process.c Thu Jan 30 19:59:31 2003 +0200 @@ -0,0 +1,233 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "fd-close-on-exec.h" +#include "env-util.h" +#include "str.h" +#include "network.h" +#include "restrict-access.h" +#include "restrict-process-size.h" +#include "var-expand.h" +#include "mail-process.h" + +#include <stdlib.h> +#include <unistd.h> +#include <grp.h> +#include <syslog.h> +#include <sys/stat.h> + +static unsigned int mail_process_count = 0; + +static int validate_uid_gid(uid_t uid, gid_t gid) +{ + if (uid == 0) { + i_error("mail process isn't allowed for root"); + return FALSE; + } + + if (uid != 0 && gid == 0) { + i_error("mail process isn't allowed to be in group 0"); + return FALSE; + } + + if (uid < (uid_t)set->first_valid_uid || + (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) { + i_error("mail process isn't allowed to use UID %s", + dec2str(uid)); + return FALSE; + } + + if (gid < (gid_t)set->first_valid_gid || + (set->last_valid_gid != 0 && gid > (gid_t)set->last_valid_gid)) { + i_error("mail process isn't allowed to use " + "GID %s (UID is %s)", dec2str(gid), dec2str(uid)); + return FALSE; + } + + return TRUE; +} + +static int validate_chroot(const char *dir) +{ + const char *const *chroot_dirs; + + if (*dir == '\0') + return FALSE; + + if (set->valid_chroot_dirs == NULL) + return FALSE; + + chroot_dirs = t_strsplit(set->valid_chroot_dirs, ":"); + while (*chroot_dirs != NULL) { + if (**chroot_dirs != '\0' && + strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0) + return TRUE; + chroot_dirs++; + } + + return FALSE; +} + +static const char *expand_mail_env(const char *env, const char *user, + const char *home) +{ + string_t *str; + const char *p; + + str = t_str_new(256); + + /* it's either type:data or just data */ + p = strchr(env, ':'); + if (p != NULL) { + while (env != p) { + str_append_c(str, *env); + env++; + } + + str_append_c(str, *env++); + } + + if (env[0] == '~' && env[1] == '/') { + /* expand home */ + str_append(str, home); + env++; + } + + /* expand %vars */ + var_expand(str, env, user, home); + return str_c(str); +} + +int create_mail_process(int socket, struct ip_addr *ip, + const char *executable, unsigned int process_size, + struct auth_master_reply *reply, const char *data) +{ + static const char *argv[] = { NULL, NULL, NULL }; + const char *host, *mail; + char title[1024]; + pid_t pid; + int i, err; + + if (mail_process_count == set->max_mail_processes) { + i_error("Maximum number of mail processes exceeded"); + return FALSE; + } + + if (!validate_uid_gid(reply->uid, reply->gid)) + return FALSE; + + if (reply->chroot && !validate_chroot(data + reply->home_idx)) + return FALSE; + + pid = fork(); + if (pid < 0) { + i_error("fork() failed: %m"); + return FALSE; + } + + if (pid != 0) { + /* master */ + mail_process_count++; + PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_MAIL); + return TRUE; + } + + clean_child_process(); + + /* move the client socket into stdin and stdout fds */ + fd_close_on_exec(socket, FALSE); + if (dup2(socket, 0) < 0) + i_fatal("mail: dup2(stdin) failed: %m"); + if (dup2(socket, 1) < 0) + i_fatal("mail: dup2(stdout) failed: %m"); + if (dup2(null_fd, 2) < 0) + i_fatal("mail: dup2(stderr) failed: %m"); + + if (close(socket) < 0) + i_error("mail: close(mail client) failed: %m"); + + /* setup environment - set the most important environment first + (paranoia about filling up environment without noticing) */ + restrict_access_set_env(data + reply->system_user_idx, + reply->uid, reply->gid, + reply->chroot ? data + reply->home_idx : NULL); + + restrict_process_size(process_size); + + env_put("LOGGED_IN=1"); + env_put(t_strconcat("HOME=", data + reply->home_idx, NULL)); + env_put(t_strconcat("MAIL_CACHE_FIELDS=", + set->mail_cache_fields, NULL)); + env_put(t_strconcat("MAIL_NEVER_CACHE_FIELDS=", + set->mail_never_cache_fields, NULL)); + env_put(t_strdup_printf("MAILBOX_CHECK_INTERVAL=%u", + set->mailbox_check_interval)); + + if (set->mail_save_crlf) + env_put("MAIL_SAVE_CRLF=1"); + if (set->mail_read_mmaped) + env_put("MAIL_READ_MMAPED=1"); + if (set->maildir_copy_with_hardlinks) + env_put("MAILDIR_COPY_WITH_HARDLINKS=1"); + if (set->maildir_check_content_changes) + env_put("MAILDIR_CHECK_CONTENT_CHANGES=1"); + if (set->overwrite_incompatible_index) + env_put("OVERWRITE_INCOMPATIBLE_INDEX=1"); + if (umask(set->umask) != set->umask) + i_fatal("Invalid umask: %o", set->umask); + + env_put(t_strconcat("MBOX_LOCKS=", set->mbox_locks, NULL)); + env_put(t_strdup_printf("MBOX_LOCK_TIMEOUT=%u", + set->mbox_lock_timeout)); + env_put(t_strdup_printf("MBOX_DOTLOCK_CHANGE_TIMEOUT=%u", + set->mbox_dotlock_change_timeout)); + if (set->mbox_read_dotlock) + env_put("MBOX_READ_DOTLOCK=1"); + + /* user given environment - may be malicious. virtual_user comes from + auth process, but don't trust that too much either. Some auth + mechanism might allow leaving extra data there. */ + mail = data + reply->mail_idx; + if (*mail == '\0' && set->default_mail_env != NULL) { + mail = expand_mail_env(set->default_mail_env, + data + reply->virtual_user_idx, + data + reply->home_idx); + } + + env_put(t_strconcat("MAIL=", mail, NULL)); + env_put(t_strconcat("USER=", data + reply->virtual_user_idx, NULL)); + + if (set->verbose_proctitle) { + host = net_ip2host(ip); + if (host == NULL) + host = "??"; + + i_snprintf(title, sizeof(title), "[%s %s]", + data + reply->virtual_user_idx, host); + argv[1] = title; + } + + /* make sure we don't leak syslog fd, but do it last so that + any errors above will be logged */ + closelog(); + + /* hide the path, it's ugly */ + argv[0] = strrchr(executable, '/'); + if (argv[0] == NULL) argv[0] = executable; else argv[0]++; + + execv(executable, (char **) argv); + err = errno; + + for (i = 0; i < 3; i++) + (void)close(i); + + i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable); + + /* not reached */ + return FALSE; +} + +void mail_process_destroyed(pid_t pid __attr_unused__) +{ + mail_process_count--; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/master/mail-process.h Thu Jan 30 19:59:31 2003 +0200 @@ -0,0 +1,12 @@ +#ifndef __MAIL_PROCESS_H +#define __MAIL_PROCESS_H + +struct auth_master_reply; + +int create_mail_process(int socket, struct ip_addr *ip, + const char *executable, unsigned int process_size, + struct auth_master_reply *reply, const char *data); + +void mail_process_destroyed(pid_t pid); + +#endif
--- a/src/master/main.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/main.c Thu Jan 30 19:59:31 2003 +0200 @@ -9,7 +9,7 @@ #include "auth-process.h" #include "login-process.h" -#include "imap-process.h" +#include "mail-process.h" #include "ssl-init.h" #include <stdio.h> @@ -33,7 +33,7 @@ struct ioloop *ioloop; struct hash_table *pids; -int null_fd, imap_fd, imaps_fd; +int null_fd, mail_fd[FD_MAX]; int validate_str(const char *str, size_t max_len) { @@ -53,18 +53,20 @@ env_clean(); /* set the failure log */ - if (set_log_path == NULL) - env_put("IMAP_USE_SYSLOG=1"); + if (set->log_path == NULL) + env_put("USE_SYSLOG=1"); else - env_put(t_strconcat("IMAP_LOGFILE=", set_log_path, NULL)); + env_put(t_strconcat("LOGFILE=", set->log_path, NULL)); - if (set_info_log_path != NULL) { - env_put(t_strconcat("IMAP_INFOLOGFILE=", - set_info_log_path, NULL)); + if (set->info_log_path != NULL) { + env_put(t_strconcat("INFOLOGFILE=", + set->info_log_path, NULL)); } - if (set_log_timestamp != NULL) - env_put(t_strconcat("IMAP_LOGSTAMP=", set_log_timestamp, NULL)); + if (set->log_timestamp != NULL) { + env_put(t_strconcat("LOGSTAMP=", + set->log_timestamp, NULL)); + } } static void sig_quit(int signo __attr_unused__) @@ -120,8 +122,8 @@ process_type = PID_GET_PROCESS_TYPE(pid); PID_REMOVE_PROCESS_TYPE(pid); - if (process_type == PROCESS_TYPE_IMAP) - imap_process_destroyed(pid); + if (process_type == PROCESS_TYPE_MAIL) + mail_process_destroyed(pid); if (process_type == PROCESS_TYPE_SSL_PARAM) ssl_parameter_process_destroyed(pid); @@ -153,13 +155,37 @@ i_warning("waitpid() failed: %m"); } -static struct ip_addr *resolve_ip(const char *name) +static struct ip_addr *resolve_ip(const char *name, unsigned int *port) { + const char *p; struct ip_addr *ip; int ret, ips_count; if (name == NULL) - return NULL; /* defaults to "*" or "::" */ + return NULL; /* defaults to "*" or "[::]" */ + + if (name[0] == '[') { + /* IPv6 address */ + p = strchr(name, ']'); + if (p == NULL) + i_fatal("Missing ']' in address %s", name); + + name = t_strdup_until(name, p); + + p++; + if (*p != '\0' && *p != ':') + i_fatal("Invalid data after ']' in address %s", name); + } else { + p = strrchr(name, ':'); + if (p != NULL) + name = t_strdup_until(name, p); + } + + if (p != NULL) { + if (!is_numeric(p+1, '\0')) + i_fatal("Invalid port in address %s", name); + *port = atoi(p+1); + } if (strcmp(name, "*") == 0) { /* IPv4 any */ @@ -168,7 +194,7 @@ return ip; } - if (strcmp(name, "::") == 0) { + if (strcmp(name, "[::]") == 0) { /* IPv6 any */ ip = t_new(struct ip_addr, 1); net_get_ip_any6(ip); @@ -190,49 +216,86 @@ static void open_fds(void) { - struct ip_addr *imap_ip, *imaps_ip; + struct ip_addr *imap_ip, *imaps_ip, *pop3_ip, *pop3s_ip, *ip; + const char *const *proto; + unsigned int imap_port = 143; + unsigned int pop3_port = 110; +#ifdef HAVE_SSL + unsigned int imaps_port = 993; + unsigned int pop3s_port = 995; +#else + unsigned int imaps_port = 0; + unsigned int pop3s_port = 0; +#endif + unsigned int port; + int *fd, i; - imap_ip = resolve_ip(set_imap_listen); - imaps_ip = resolve_ip(set_imaps_listen); + /* resolve */ + imap_ip = resolve_ip(set->imap_listen, &imap_port); + imaps_ip = resolve_ip(set->imaps_listen, &imaps_port); + pop3_ip = resolve_ip(set->pop3_listen, &pop3_port); + pop3s_ip = resolve_ip(set->pop3s_listen, &pop3s_port); - if (imaps_ip == NULL && set_imaps_listen == NULL) + if (imaps_ip == NULL && set->imaps_listen == NULL) imaps_ip = imap_ip; + if (pop3s_ip == NULL && set->pop3s_listen == NULL) + pop3s_ip = pop3_ip; + /* initialize fds */ null_fd = open("/dev/null", O_RDONLY); if (null_fd == -1) i_fatal("Can't open /dev/null: %m"); fd_close_on_exec(null_fd, TRUE); - imap_fd = set_imap_port == 0 ? dup(null_fd) : - net_listen(imap_ip, &set_imap_port); - if (imap_fd == -1) - i_fatal("listen(%d) failed: %m", set_imap_port); - fd_close_on_exec(imap_fd, TRUE); + for (i = 0; i < FD_MAX; i++) + mail_fd[i] = -1; + + /* register wanted protocols */ + for (proto = t_strsplit(set->protocols, " "); *proto != NULL; proto++) { + if (strcasecmp(*proto, "imap") == 0) { + fd = &mail_fd[FD_IMAP]; ip = imap_ip; port = imap_port; + } else if (strcasecmp(*proto, "imaps") == 0) { + fd = &mail_fd[FD_IMAPS]; ip = imaps_ip; port = imaps_port; + } else if (strcasecmp(*proto, "pop3") == 0) { + fd = &mail_fd[FD_POP3]; ip = pop3_ip; port = pop3_port; + } else if (strcasecmp(*proto, "pop3s") == 0) { + fd = &mail_fd[FD_POP3S]; ip = pop3s_ip; port = pop3s_port; + } else { + i_fatal("Unknown protocol %s", *proto); + } -#ifdef HAVE_SSL - imaps_fd = set_ssl_disable || set_imaps_port == 0 ? dup(null_fd) : - net_listen(imaps_ip, &set_imaps_port); -#else - imaps_fd = dup(null_fd); -#endif - if (imaps_fd == -1) - i_fatal("listen(%d) failed: %m", set_imaps_port); - fd_close_on_exec(imaps_fd, TRUE); + if (*fd != -1) + i_fatal("Protocol %s given more than once", *proto); + + *fd = port == 0 ? dup(null_fd) : net_listen(ip, &port); + if (*fd == -1) + i_fatal("listen(%d) failed: %m", port); + fd_close_on_exec(*fd, TRUE); + } + + for (i = 0; i < FD_MAX; i++) { + if (mail_fd[i] == -1) { + mail_fd[i] = dup(null_fd); + if (mail_fd[i] == -1) + i_fatal("dup(mail_fd[%d]) failed: %m", i); + fd_close_on_exec(mail_fd[i], TRUE); + } + } } static void open_logfile(void) { - if (set_log_path == NULL) - i_set_failure_syslog("imap-master", LOG_NDELAY, LOG_MAIL); + if (set->log_path == NULL) + i_set_failure_syslog("dovecot", LOG_NDELAY, LOG_MAIL); else { /* log to file or stderr */ - i_set_failure_file(set_log_path, "imap-master"); + i_set_failure_file(set->log_path, "dovecot"); } - if (set_info_log_path != NULL) - i_set_info_file(set_info_log_path); + if (set->info_log_path != NULL) + i_set_info_file(set->info_log_path); - i_set_failure_timestamp_format(set_log_timestamp); + i_set_failure_timestamp_format(set->log_timestamp); i_info("Dovecot starting up"); } @@ -256,6 +319,8 @@ static void main_deinit(void) { + int i; + if (lib_signal_kill != 0) i_warning("Killed with signal %d", lib_signal_kill); @@ -270,10 +335,11 @@ if (close(null_fd) < 0) i_error("close(null_fd) failed: %m"); - if (close(imap_fd) < 0) - i_error("close(imap_fd) failed: %m"); - if (close(imaps_fd) < 0) - i_error("close(imaps_fd) failed: %m"); + + for (i = 0; i < FD_MAX; i++) { + if (close(mail_fd[i]) < 0) + i_error("close(mail_fd[%d]) failed: %m", i); + } hash_destroy(pids); closelog(); @@ -296,7 +362,7 @@ static void print_help(void) { - printf("Usage: imap-master [-F] [-c <config file>]\n"); + printf("Usage: dovecot [-F] [-c <config file>]\n"); } int main(int argc, char *argv[])
--- a/src/master/master-login-interface.h Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/master-login-interface.h Thu Jan 30 19:59:31 2003 +0200 @@ -4,8 +4,8 @@ #include "network.h" #define LOGIN_MASTER_SOCKET_FD 0 -#define LOGIN_IMAP_LISTEN_FD 1 -#define LOGIN_IMAPS_LISTEN_FD 2 +#define LOGIN_LISTEN_FD 1 +#define LOGIN_SSL_LISTEN_FD 2 struct master_login_request { unsigned int tag;
--- a/src/master/settings.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/settings.c Thu Jan 30 19:59:31 2003 +0200 @@ -7,6 +7,7 @@ #include "settings.h" #include <stdio.h> +#include <stddef.h> #include <unistd.h> #include <fcntl.h> #include <pwd.h> @@ -17,157 +18,224 @@ SET_BOOL }; -struct setting { +struct setting_def { + enum setting_type type; const char *name; - enum setting_type type; - void *ptr; + size_t offset; }; -static struct setting settings[] = { - { "base_dir", SET_STR, &set_base_dir }, - { "log_path", SET_STR, &set_log_path }, - { "info_log_path", SET_STR, &set_info_log_path }, - { "log_timestamp", SET_STR, &set_log_timestamp }, +#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, imap_listen), + DEF(SET_STR, imaps_listen), + DEF(SET_STR, pop3_listen), + DEF(SET_STR, pop3s_listen), - { "imap_port", SET_INT, &set_imap_port }, - { "imaps_port", SET_INT, &set_imaps_port }, - { "imap_listen", SET_STR, &set_imap_listen }, - { "imaps_listen", SET_STR, &set_imaps_listen }, - { "ssl_disable", SET_BOOL,&set_ssl_disable, }, - { "ssl_cert_file", SET_STR, &set_ssl_cert_file }, - { "ssl_key_file", SET_STR, &set_ssl_key_file }, - { "ssl_parameters_file",SET_STR, &set_ssl_parameters_file }, - { "ssl_parameters_regenerate", - SET_INT, &set_ssl_parameters_regenerate }, - { "disable_plaintext_auth", - SET_BOOL,&set_disable_plaintext_auth }, + DEF(SET_BOOL, ssl_disable), + 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_BOOL, disable_plaintext_auth), - { "login_executable", SET_STR, &set_login_executable }, - { "login_user", SET_STR, &set_login_user }, - { "login_process_size", SET_INT, &set_login_process_size }, - { "login_dir", SET_STR, &set_login_dir }, - { "login_chroot", SET_BOOL,&set_login_chroot }, - { "login_process_per_connection", - SET_BOOL,&set_login_process_per_connection }, - { "login_processes_count", - SET_INT, &set_login_processes_count }, - { "max_logging_users", SET_INT, &set_max_logging_users }, + /* login */ + DEF(SET_STR, login_dir), + DEF(SET_BOOL, login_chroot), + + /* mail */ + DEF(SET_STR, valid_chroot_dirs), + 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), - { "imap_executable", SET_STR, &set_imap_executable }, - { "imap_process_size", SET_INT, &set_imap_process_size }, - { "valid_chroot_dirs", SET_STR, &set_valid_chroot_dirs }, - { "max_imap_processes", SET_INT, &set_max_imap_processes }, - { "verbose_proctitle", SET_BOOL,&set_verbose_proctitle }, - { "first_valid_uid", SET_INT, &set_first_valid_uid }, - { "last_valid_uid", SET_INT, &set_last_valid_uid }, - { "first_valid_gid", SET_INT, &set_first_valid_gid }, - { "last_valid_gid", SET_INT, &set_last_valid_gid }, - { "default_mail_env", SET_STR, &set_default_mail_env }, - { "mail_cache_fields", SET_STR, &set_mail_cache_fields }, - { "mail_never_cache_fields", - SET_STR, &set_mail_never_cache_fields }, - { "mailbox_check_interval", - SET_INT, &set_mailbox_check_interval }, - { "mail_save_crlf", SET_BOOL,&set_mail_save_crlf }, - { "mail_read_mmaped", SET_BOOL,&set_mail_read_mmaped }, - { "maildir_copy_with_hardlinks", - SET_BOOL,&set_maildir_copy_with_hardlinks }, - { "maildir_check_content_changes", - SET_BOOL,&set_maildir_check_content_changes }, - { "mbox_locks", SET_STR, &set_mbox_locks, }, - { "mbox_read_dotlock", SET_BOOL,&set_mbox_read_dotlock, }, - { "mbox_lock_timeout", SET_INT, &set_mbox_lock_timeout, }, - { "mbox_dotlock_change_timeout", - SET_INT, &set_mbox_dotlock_change_timeout, }, - { "overwrite_incompatible_index", - SET_BOOL,&set_overwrite_incompatible_index }, - { "umask", SET_INT, &set_umask }, + DEF(SET_STR, default_mail_env), + DEF(SET_STR, mail_cache_fields), + DEF(SET_STR, mail_never_cache_fields), + DEF(SET_STR, mailbox_check_interval), + DEF(SET_STR, mail_save_crlf), + DEF(SET_STR, mail_read_mmaped), + DEF(SET_STR, maildir_copy_with_hardlinks), + DEF(SET_STR, maildir_check_content_changes), + DEF(SET_STR, mbox_locks), + DEF(SET_STR, mbox_read_dotlock), + DEF(SET_STR, mbox_lock_timeout), + DEF(SET_STR, mbox_dotlock_change_timeout), + DEF(SET_STR, overwrite_incompatible_index), + DEF(SET_STR, umask), + + /* imap */ + DEF(SET_STR, imap_executable), + DEF(SET_INT, imap_process_size), - { NULL, 0, NULL } + /* pop3 */ + DEF(SET_STR, pop3_executable), + DEF(SET_INT, pop3_process_size), + + { 0, NULL, 0 } +}; + +#undef DEF +#define DEF(type, name) \ + { type, #name, offsetof(struct login_settings, name) } + +static struct setting_def login_setting_defs[] = { + DEF(SET_STR, executable), + DEF(SET_STR, user), + + DEF(SET_BOOL, process_per_connection), + + DEF(SET_INT, process_size), + DEF(SET_INT, processes_count), + DEF(SET_INT, max_processes_count), + DEF(SET_INT, max_logging_users), + + { 0, NULL, 0 } }; -/* common */ -char *set_base_dir = PKG_RUNDIR; -char *set_log_path = NULL; -char *set_info_log_path = NULL; -char *set_log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT; +#undef DEF +#define DEF(type, name) \ + { type, #name, offsetof(struct auth_settings, name) } -/* general */ -unsigned int set_imap_port = 143; -unsigned int set_imaps_port = 993; -char *set_imap_listen = "*"; -char *set_imaps_listen = NULL; +static struct setting_def auth_setting_defs[] = { + DEF(SET_STR, mechanisms), + DEF(SET_STR, realms), + DEF(SET_STR, userdb), + DEF(SET_STR, passdb), + DEF(SET_STR, executable), + DEF(SET_STR, user), + DEF(SET_STR, chroot), + + DEF(SET_BOOL, use_cyrus_sasl), + DEF(SET_BOOL, verbose), + + DEF(SET_INT, count), + DEF(SET_INT, process_size), + + { 0, NULL, 0 } +}; -int set_ssl_disable = FALSE; -char *set_ssl_cert_file = SSLDIR"/certs/imapd.pem"; -char *set_ssl_key_file = SSLDIR"/private/imapd.pem"; -char *set_ssl_parameters_file = "ssl-parameters.dat"; -unsigned int set_ssl_parameters_regenerate = 24; -int set_disable_plaintext_auth = FALSE; +struct settings default_settings = { + /* 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(imap_listen) "*", + MEMBER(imaps_listen) NULL, + MEMBER(pop3_listen) "*", + MEMBER(pop3s_listen) NULL, -/* login */ -char *set_login_executable = PKG_LIBEXECDIR"/imap-login"; -unsigned int set_login_process_size = 16; -char *set_login_user = "imapd"; -char *set_login_dir = "login"; + MEMBER(ssl_disable) FALSE, + 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(disable_plaintext_auth) FALSE, -int set_login_chroot = TRUE; -int set_login_process_per_connection = TRUE; -unsigned int set_login_processes_count = 3; -unsigned int set_login_max_processes_count = 128; -unsigned int set_max_logging_users = 256; + /* login */ + MEMBER(login_dir) "login", + MEMBER(login_chroot) TRUE, -uid_t set_login_uid; /* generated from set_login_user */ -gid_t set_login_gid; /* generated from set_login_user */ + /* mail */ + MEMBER(valid_chroot_dirs) NULL, + MEMBER(max_mail_processes) 1024, + MEMBER(verbose_proctitle) FALSE, -/* imap */ -char *set_imap_executable = PKG_LIBEXECDIR"/imap"; -unsigned int set_imap_process_size = 256; -char *set_valid_chroot_dirs = NULL; -unsigned int set_max_imap_processes = 1024; -int set_verbose_proctitle = FALSE; + MEMBER(first_valid_uid) 500, + MEMBER(last_valid_uid) 0, + MEMBER(first_valid_gid) 1, + MEMBER(last_valid_gid) 0, -unsigned int set_first_valid_uid = 500, set_last_valid_uid = 0; -unsigned int set_first_valid_gid = 1, set_last_valid_gid = 0; + MEMBER(default_mail_env) NULL, + MEMBER(mail_cache_fields) "MessagePart", + MEMBER(mail_never_cache_fields) NULL, + MEMBER(mailbox_check_interval) 0, + MEMBER(mail_save_crlf) FALSE, + MEMBER(mail_read_mmaped) FALSE, + MEMBER(maildir_copy_with_hardlinks) FALSE, + MEMBER(maildir_check_content_changes) FALSE, + MEMBER(mbox_locks) "dotlock fcntl flock", + MEMBER(mbox_read_dotlock) FALSE, + MEMBER(mbox_lock_timeout) 300, + MEMBER(mbox_dotlock_change_timeout) 30, + MEMBER(overwrite_incompatible_index) FALSE, + MEMBER(umask) 0077, + + /* imap */ + MEMBER(imap_executable) PKG_LIBEXECDIR"/imap", + MEMBER(imap_process_size) 256, + + /* pop3 */ + MEMBER(pop3_executable) PKG_LIBEXECDIR"/pop3", + MEMBER(pop3_process_size) 256, -char *set_default_mail_env = NULL; -char *set_mail_cache_fields = "MessagePart"; -char *set_mail_never_cache_fields = NULL; -unsigned int set_mailbox_check_interval = 0; -int set_mail_save_crlf = FALSE; -int set_mail_read_mmaped = FALSE; -int set_maildir_copy_with_hardlinks = FALSE; -int set_maildir_check_content_changes = FALSE; -char *set_mbox_locks = "dotlock fcntl flock"; -int set_mbox_read_dotlock = FALSE; -unsigned int set_mbox_lock_timeout = 300; -unsigned int set_mbox_dotlock_change_timeout = 30; -int set_overwrite_incompatible_index = FALSE; -unsigned int set_umask = 0077; + MEMBER(login_gid) 0, + MEMBER(auths) NULL, + MEMBER(logins) NULL +}; + +struct login_settings default_login_settings = { + MEMBER(next) NULL, + MEMBER(name) NULL, + + MEMBER(executable) NULL, + MEMBER(user) "dovecot", + + MEMBER(process_per_connection) TRUE, -/* auth */ -struct auth_config *auth_processes_config = NULL; + MEMBER(process_size) 16, + MEMBER(processes_count) 3, + MEMBER(max_processes_count) 128, + MEMBER(max_logging_users) 256, -static void fix_base_path(char **str) + MEMBER(uid) 0 /* generated */ +}; + +static pool_t settings_pool; +struct settings *set = NULL; + +static void fix_base_path(struct settings *set, const char **str) { - char *fullpath; - if (*str != NULL && **str != '\0' && **str != '/') { - fullpath = i_strconcat(set_base_dir, "/", *str, NULL); - i_free(*str); - *str = i_strdup(fullpath); + *str = p_strconcat(settings_pool, + set->base_dir, "/", *str, NULL); } } -static void get_login_uid(void) +static void get_login_uid(struct settings *set, + struct login_settings *login_set) { struct passwd *pw; - if ((pw = getpwnam(set_login_user)) == NULL) - i_fatal("Login user doesn't exist: %s", set_login_user); + if ((pw = getpwnam(login_set->user)) == NULL) + i_fatal("Login user doesn't exist: %s", login_set->user); - set_login_uid = pw->pw_uid; - set_login_gid = pw->pw_gid; + if (set->login_gid == 0) + set->login_gid = pw->pw_gid; + else if (set->login_gid != pw->pw_gid) { + i_fatal("All login process users must belong to same group " + "(%s vs %s)", dec2str(set->login_gid), + dec2str(pw->pw_gid)); + } + + login_set->uid = pw->pw_uid; } static const char *get_bool(const char *value, int *result) @@ -182,22 +250,37 @@ return NULL; } -static void auth_settings_verify(void) +static const char *get_uint(const char *value, unsigned int *result) { - struct auth_config *auth; + int num; + + if (!sscanf(value, "%i", &num) || num < 0) + return t_strconcat("Invalid number: ", value, NULL); + *result = num; + return NULL; +} + +static void auth_settings_verify(struct auth_settings *auth) +{ + if (access(auth->executable, X_OK) < 0) + i_fatal("Can't use auth executable %s: %m", auth->executable); - for (auth = auth_processes_config; auth != NULL; auth = auth->next) { - if (access(auth->executable, X_OK) < 0) { - i_fatal("Can't use auth executable %s: %m", - auth->executable); - } + fix_base_path(set, &auth->chroot); + if (auth->chroot != NULL && access(auth->chroot, X_OK) < 0) { + i_fatal("Can't access auth chroot directory %s: %m", + auth->chroot); + } +} - fix_base_path(&auth->chroot); - if (auth->chroot != NULL && access(auth->chroot, X_OK) < 0) { - i_fatal("Can't access auth chroot directory %s: %m", - auth->chroot); - } - } +static void login_settings_verify(struct login_settings *login) +{ + if (access(login->executable, X_OK) < 0) + i_fatal("Can't use login executable %s: %m", login->executable); + + if (login->processes_count < 1) + i_fatal("login_processes_count must be at least 1"); + if (login->max_logging_users < 1) + i_fatal("max_logging_users must be at least 1"); } static const char *get_directory(const char *path) @@ -214,86 +297,91 @@ } } -static void settings_verify(void) +static void settings_verify(struct settings *set) { + struct login_settings *login; + struct auth_settings *auth; const char *const *str; const char *dir; int dotlock_got, fcntl_got, flock_got; - get_login_uid(); - - if (access(set_login_executable, X_OK) < 0) { - i_fatal("Can't use login executable %s: %m", - set_login_executable); + for (login = set->logins; login != NULL; login = login->next) { + get_login_uid(set, login); + login_settings_verify(login); } - if (access(set_imap_executable, X_OK) < 0) { - i_fatal("Can't use imap executable %s: %m", - set_imap_executable); + if (strstr(set->protocols, "imap") != NULL) { + if (access(set->imap_executable, X_OK) < 0) { + i_fatal("Can't use imap executable %s: %m", + set->imap_executable); + } } - if (set_log_path != NULL) { - dir = get_directory(set_log_path); + if (strstr(set->protocols, "pop3") != NULL) { + if (access(set->pop3_executable, X_OK) < 0) { + i_fatal("Can't use pop3 executable %s: %m", + set->pop3_executable); + } + } + + if (set->log_path != NULL) { + dir = get_directory(set->log_path); if (access(dir, W_OK) < 0) i_fatal("Can't access log directory %s: %m", dir); } - if (set_info_log_path != NULL) { - dir = get_directory(set_info_log_path); + if (set->info_log_path != NULL) { + dir = get_directory(set->info_log_path); if (access(dir, W_OK) < 0) i_fatal("Can't access info log directory %s: %m", dir); } #ifdef HAVE_SSL - if (!set_ssl_disable) { - if (access(set_ssl_cert_file, R_OK) < 0) { + if (!set->ssl_disable) { + if (access(set->ssl_cert_file, R_OK) < 0) { i_fatal("Can't use SSL certificate %s: %m", - set_ssl_cert_file); + set->ssl_cert_file); } - if (access(set_ssl_key_file, R_OK) < 0) { + if (access(set->ssl_key_file, R_OK) < 0) { i_fatal("Can't use SSL key file %s: %m", - set_ssl_key_file); + set->ssl_key_file); } } #endif /* fix relative paths */ - fix_base_path(&set_ssl_parameters_file); - fix_base_path(&set_login_dir); + 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, geteuid(), getegid()) == 0) { + if (safe_mkdir(set->base_dir, 0700, geteuid(), getegid()) == 0) { i_warning("Corrected permissions for base directory %s", PKG_RUNDIR); } /* wipe out contents of login directory, if it exists */ - if (unlink_directory(set_login_dir, FALSE) < 0) - i_fatal("unlink_directory() failed for %s: %m", set_login_dir); + if (unlink_directory(set->login_dir, FALSE) < 0) + i_fatal("unlink_directory() failed for %s: %m", set->login_dir); - if (safe_mkdir(set_login_dir, 0750, geteuid(), set_login_gid) == 0) { + if (safe_mkdir(set->login_dir, 0750, geteuid(), set->login_gid) == 0) { i_warning("Corrected permissions for login directory %s", - set_login_dir); + set->login_dir); } - if (set_max_imap_processes < 1) - i_fatal("max_imap_processes must be at least 1"); - if (set_login_processes_count < 1) - i_fatal("login_processes_count must be at least 1"); - if (set_max_logging_users < 1) - i_fatal("max_logging_users must be at least 1"); + if (set->max_mail_processes < 1) + i_fatal("max_mail_processes must be at least 1"); - if (set_last_valid_uid != 0 && - set_first_valid_uid > set_last_valid_uid) + if (set->last_valid_uid != 0 && + set->first_valid_uid > set->last_valid_uid) i_fatal("first_valid_uid can't be larger than last_valid_uid"); - if (set_last_valid_gid != 0 && - set_first_valid_gid > set_last_valid_gid) + if (set->last_valid_gid != 0 && + set->first_valid_gid > set->last_valid_gid) i_fatal("first_valid_gid can't be larger than last_valid_gid"); dotlock_got = fcntl_got = flock_got = FALSE; - for (str = t_strsplit(set_mbox_locks, " "); *str != NULL; str++) { + for (str = t_strsplit(set->mbox_locks, " "); *str != NULL; str++) { if (strcasecmp(*str, "dotlock") == 0) dotlock_got = TRUE; else if (strcasecmp(*str, "fcntl") == 0) @@ -315,189 +403,140 @@ if (!dotlock_got && !fcntl_got && !flock_got) i_fatal("mbox_locks: No mbox locking methods selected"); - if (dotlock_got && !set_mbox_read_dotlock && !fcntl_got && !flock_got) { + if (dotlock_got && !set->mbox_read_dotlock && + !fcntl_got && !flock_got) { i_warning("mbox_locks: Only dotlock selected, forcing " "mbox_read_dotlock = yes to avoid corruption."); - set_mbox_read_dotlock = TRUE; + set->mbox_read_dotlock = TRUE; } - auth_settings_verify(); + for (auth = set->auths; auth != NULL; auth = auth->next) + auth_settings_verify(auth); } -static struct auth_config *auth_config_new(const char *name) +static void auth_settings_new(struct settings *set, const char *name) { - struct auth_config *auth; + struct auth_settings *auth; - auth = i_new(struct auth_config, 1); - auth->name = i_strdup(name); - auth->executable = i_strdup(PKG_LIBEXECDIR"/imap-auth"); + auth = p_new(settings_pool, struct auth_settings, 1); + auth->name = p_strdup(settings_pool, name); + auth->executable = p_strdup(settings_pool, + PKG_LIBEXECDIR"/dovecot-auth"); auth->count = 1; - auth->next = auth_processes_config; - auth_processes_config = auth; - return auth; + auth->next = set->auths; + set->auths = auth; } -static void auth_config_free(struct auth_config *auth) +static const char *parse_new_auth(struct settings *set, const char *name) { - i_free(auth->name); - i_free(auth->mechanisms); - i_free(auth->realms); - i_free(auth->userdb); - i_free(auth->userdb_args); - i_free(auth->passdb); - i_free(auth->passdb_args); - i_free(auth->executable); - i_free(auth->user); - i_free(auth->chroot); - i_free(auth); -} - -static const char *parse_new_auth(const char *name) -{ - struct auth_config *auth; + struct auth_settings *auth; if (strchr(name, '/') != NULL) return "Authentication process name must not contain '/'"; - for (auth = auth_processes_config; auth != NULL; auth = auth->next) { + for (auth = set->auths; auth != NULL; auth = auth->next) { if (strcmp(auth->name, name) == 0) { return "Authentication process already exists " "with the same name"; } } - (void)auth_config_new(name); + auth_settings_new(set, name); return NULL; } -static const char *parse_auth(const char *key, const char *value) +static void login_settings_new(struct settings *set, const char *name) { - struct auth_config *auth = auth_processes_config; - const char *p; - char **ptr; + struct login_settings *login; - if (auth == NULL) - return "Authentication process name not defined yet"; + login = p_new(settings_pool, struct login_settings, 1); - /* check the easy string values first */ - if (strcmp(key, "auth_mechanisms") == 0) - ptr = &auth->mechanisms; - else if (strcmp(key, "auth_realms") == 0) - ptr = &auth->realms; - else if (strcmp(key, "auth_executable") == 0) - ptr = &auth->executable; - else if (strcmp(key, "auth_user") == 0) - ptr = &auth->user; - else if (strcmp(key, "auth_chroot") == 0) - ptr = &auth->chroot; - else - ptr = NULL; + /* copy defaults */ + *login = set->logins != NULL ? *set->logins : + default_login_settings; - if (ptr != NULL) { - i_free(*ptr); - *ptr = i_strdup(value); - return NULL; - } - - if (strcmp(key, "auth_userdb") == 0) { - /* split it into userdb + userdb_args */ - for (p = value; *p != ' ' && *p != '\0'; ) - p++; - - i_free(auth->userdb); - auth->userdb = i_strdup_until(value, p); - - while (*p == ' ') p++; - - i_free(auth->userdb_args); - auth->userdb_args = i_strdup(p); - return NULL; + if (strcasecmp(name, "imap") == 0) { + login->name = "imap"; + login->executable = PKG_LIBEXECDIR"/imap-login"; + } else if (strcasecmp(name, "pop3") == 0) { + login->name = "pop3"; + login->executable = PKG_LIBEXECDIR"/pop3-login"; + } else { + i_fatal("Unknown login process type '%s'", name); } - if (strcmp(key, "auth_passdb") == 0) { - /* split it into passdb + passdb_args */ - for (p = value; *p != ' ' && *p != '\0'; ) - p++; + login->next = set->logins; + set->logins = login; +} - i_free(auth->passdb); - auth->passdb = i_strdup_until(value, p); +static const char *parse_new_login(struct settings *set, const char *name) +{ + struct login_settings *login; - while (*p == ' ') p++; - - i_free(auth->passdb_args); - auth->passdb_args = i_strdup(p); - return NULL; + for (login = set->logins; login != NULL; login = login->next) { + if (strcmp(login->name, name) == 0) { + return "Login process already exists " + "with the same name"; + } } - if (strcmp(key, "auth_cyrus_sasl") == 0) - return get_bool(value, &auth->use_cyrus_sasl); - - if (strcmp(key, "auth_verbose") == 0) - return get_bool(value, &auth->verbose); - - if (strcmp(key, "auth_count") == 0) { - int num; - - if (!sscanf(value, "%i", &num) || num < 0) - return t_strconcat("Invalid number: ", value, NULL); - auth->count = num; - return NULL; - } - - if (strcmp(key, "auth_process_size") == 0) { - int num; - - if (!sscanf(value, "%i", &num) || num < 0) - return t_strconcat("Invalid number: ", value, NULL); - auth->process_size = num; - return NULL; - } - - return t_strconcat("Unknown setting: ", key, NULL); + login_settings_new(set, name); + return NULL; } -static const char *parse_setting(const char *key, const char *value) +static const char * +parse_setting_from_defs(struct setting_def *defs, void *base, + const char *key, const char *value) { - struct setting *set; + struct setting_def *def; - if (strcmp(key, "auth") == 0) - return parse_new_auth(value); - if (strncmp(key, "auth_", 5) == 0) - return parse_auth(key, value); + for (def = defs; def->name != NULL; def++) { + if (strcmp(def->name, key) == 0) { + void *ptr = STRUCT_MEMBER_P(base, def->offset); - for (set = settings; set->name != NULL; set++) { - if (strcmp(set->name, key) == 0) { - switch (set->type) { + switch (def->type) { case SET_STR: - i_free(*((char **)set->ptr)); - *((char **)set->ptr) = i_strdup_empty(value); - break; + *((char **) ptr) = + p_strdup_empty(settings_pool, value); + return NULL; case SET_INT: /* use %i so we can handle eg. 0600 as octal value with umasks */ - if (!sscanf(value, "%i", (int *) set->ptr)) - return t_strconcat("Invalid number: ", - value, NULL); - break; + return get_uint(value, (unsigned int *) ptr); case SET_BOOL: - return get_bool(value, set->ptr); + return get_bool(value, (int *) ptr); } - return NULL; } } return t_strconcat("Unknown setting: ", key, NULL); } -static void settings_free(void) +static const char *parse_setting(struct settings *set, + const char *key, const char *value) { - while (auth_processes_config != NULL) { - struct auth_config *auth = auth_processes_config; + if (strcmp(key, "auth") == 0) + return parse_new_auth(set, value); + if (strncmp(key, "auth_", 5) == 0) { + if (set->auths == NULL) + return "Authentication process name not defined yet"; + + return parse_setting_from_defs(auth_setting_defs, + set->auths, key + 5, value); + } - auth_processes_config = auth->next; - auth_config_free(auth); + if (strcmp(key, "login") == 0) + return parse_new_login(set, value); + if (strncmp(key, "login_", 6) == 0) { + if (set->logins == NULL) + return "Login process name not defined yet"; + + return parse_setting_from_defs(login_setting_defs, + set->logins, key + 6, value); } + + return parse_setting_from_defs(setting_defs, set, key, value); } #define IS_WHITE(c) ((c) == ' ' || (c) == '\t') @@ -509,7 +548,9 @@ char *line, *key, *p; int fd, linenum; - settings_free(); + p_clear(settings_pool); + set = p_new(settings_pool, struct settings, 1); + *set = default_settings; fd = open(path, O_RDONLY); if (fd < 0) @@ -558,7 +599,7 @@ p--; *p = '\0'; - errormsg = parse_setting(key, line); + errormsg = parse_setting(set, key, line); } if (errormsg != NULL) { @@ -569,18 +610,10 @@ i_stream_unref(input); - settings_verify(); + settings_verify(set); } void settings_init(void) { - struct setting *set; - - /* strdup() all default settings */ - for (set = settings; set->name != NULL; set++) { - if (set->type == SET_STR) { - char **str = set->ptr; - *str = i_strdup(*str); - } - } + settings_pool = pool_alloconly_create("settings", 1024); }
--- a/src/master/settings.h Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/settings.h Thu Jan 30 19:59:31 2003 +0200 @@ -1,76 +1,97 @@ #ifndef __SETTINGS_H #define __SETTINGS_H -/* common */ -extern char *set_base_dir; -extern char *set_log_path; -extern char *set_info_log_path; -extern char *set_log_timestamp; +struct settings { + /* common */ + const char *base_dir; + const char *log_path; + const char *info_log_path; + const char *log_timestamp; -/* general */ -extern unsigned int set_imap_port; -extern unsigned int set_imaps_port; -extern char *set_imap_listen; -extern char *set_imaps_listen; + /* general */ + const char *protocols; + const char *imap_listen; + const char *imaps_listen; + const char *pop3_listen; + const char *pop3s_listen; -extern int set_ssl_disable; -extern char *set_ssl_cert_file; -extern char *set_ssl_key_file; -extern char *set_ssl_parameters_file; -extern unsigned int set_ssl_parameters_regenerate; -extern int set_disable_plaintext_auth; + int ssl_disable; + const char *ssl_cert_file; + const char *ssl_key_file; + const char *ssl_parameters_file; + unsigned int ssl_parameters_regenerate; + int disable_plaintext_auth; -/* login */ -extern char *set_login_executable; -extern char *set_login_user; -extern unsigned int set_login_process_size; -extern char *set_login_dir; -extern int set_login_chroot; -extern int set_login_process_per_connection; -extern unsigned int set_login_processes_count; -extern unsigned int set_login_max_processes_count; -extern unsigned int set_max_logging_users; + /* login */ + const char *login_dir; + int login_chroot; -extern uid_t set_login_uid; -extern gid_t set_login_gid; + /* mail */ + const char *valid_chroot_dirs; + unsigned int max_mail_processes; + int verbose_proctitle; + + unsigned int first_valid_uid, last_valid_uid; + unsigned int first_valid_gid, last_valid_gid; -/* imap */ -extern char *set_imap_executable; -extern unsigned int set_imap_process_size; -extern char *set_valid_chroot_dirs; -extern unsigned int set_max_imap_processes; -extern int set_verbose_proctitle; + const char *default_mail_env; + const char *mail_cache_fields; + const char *mail_never_cache_fields; + unsigned int mailbox_check_interval; + int mail_save_crlf; + int mail_read_mmaped; + int maildir_copy_with_hardlinks; + int maildir_check_content_changes; + char *mbox_locks; + int mbox_read_dotlock; + unsigned int mbox_lock_timeout; + unsigned int mbox_dotlock_change_timeout; + int overwrite_incompatible_index; + unsigned int umask; -extern unsigned int set_first_valid_uid, set_last_valid_uid; -extern unsigned int set_first_valid_gid, set_last_valid_gid; + /* imap */ + const char *imap_executable; + unsigned int imap_process_size; + + /* imap */ + const char *pop3_executable; + unsigned int pop3_process_size; + + /* .. */ + gid_t login_gid; -extern char *set_default_mail_env; -extern char *set_mail_cache_fields; -extern char *set_mail_never_cache_fields; -extern unsigned int set_mailbox_check_interval; -extern int set_mail_save_crlf; -extern int set_mail_read_mmaped; -extern int set_maildir_copy_with_hardlinks; -extern int set_maildir_check_content_changes; -extern char *set_mbox_locks; -extern int set_mbox_read_dotlock; -extern unsigned int set_mbox_lock_timeout; -extern unsigned int set_mbox_dotlock_change_timeout; -extern int set_overwrite_incompatible_index; -extern unsigned int set_umask; + struct auth_settings *auths; + struct login_settings *logins; +}; + +struct login_settings { + struct login_settings *next; + + const char *name; + const char *executable; + const char *user; + + int process_per_connection; -/* auth */ -struct auth_config { - struct auth_config *next; + unsigned int process_size; + unsigned int processes_count; + unsigned int max_processes_count; + unsigned int max_logging_users; + + uid_t uid; /* gid must be always same with all login processes */ +}; - char *name; - char *mechanisms; - char *realms; - char *userdb, *userdb_args; - char *passdb, *passdb_args; - char *executable; - char *user; - char *chroot; +struct auth_settings { + struct auth_settings *next; + + const char *name; + const char *mechanisms; + const char *realms; + const char *userdb; + const char *passdb; + const char *executable; + const char *user; + const char *chroot; int use_cyrus_sasl, verbose; @@ -78,7 +99,7 @@ unsigned int process_size; }; -extern struct auth_config *auth_processes_config; +extern struct settings *set; void settings_read(const char *path);
--- a/src/master/ssl-init.c Thu Jan 30 19:56:19 2003 +0200 +++ b/src/master/ssl-init.c Thu Jan 30 19:59:31 2003 +0200 @@ -50,7 +50,7 @@ if (pid == 0) { /* child */ - generate_parameters_file(set_ssl_parameters_file); + generate_parameters_file(set->ssl_parameters_file); exit(0); } else { /* parent */ @@ -69,13 +69,13 @@ struct stat st; time_t regen_time; - if (set_ssl_parameters_file == NULL || set_ssl_disable || generating) + if (set->ssl_parameters_file == NULL || set->ssl_disable || generating) return; - if (lstat(set_ssl_parameters_file, &st) < 0) { + if (lstat(set->ssl_parameters_file, &st) < 0) { if (errno != ENOENT) { i_error("lstat() failed for SSL parameters file %s: %m", - set_ssl_parameters_file); + set->ssl_parameters_file); return; } @@ -83,7 +83,8 @@ } /* make sure it's new enough and the permissions are correct */ - regen_time = st.st_mtime + (time_t)(set_ssl_parameters_regenerate*3600); + regen_time = st.st_mtime + + (time_t)(set->ssl_parameters_regenerate*3600); if (regen_time < ioloop_time || (st.st_mode & 077) != 0 || st.st_uid != geteuid() || st.st_gid != getegid()) start_generate_process();