From: Timo Sirainen Date: Fri, 9 Jul 2004 19:59:02 +0000 (+0300) Subject: Added --exec-mail option to master. It can be used to parse Dovecot config X-Git-Tag: 1.1.alpha1~3795 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=91d04d91efc97f1cc91997c6e2df22f7432d52e0;p=thirdparty%2Fdovecot%2Fcore.git Added --exec-mail option to master. It can be used to parse Dovecot config file and exec() imap/pop3 process directly. Moved --inetd option into environment as it's only for internal use. --HG-- branch : HEAD --- diff --git a/src/login-common/master.c b/src/login-common/master.c index 9f68449d6a..dc22ba1bd6 100644 --- a/src/login-common/master.c +++ b/src/login-common/master.c @@ -104,7 +104,7 @@ void master_close(void) static void master_exec(int fd) { - char *argv[] = { "dovecot", "--inetd", NULL }; + char *argv[] = { "dovecot", NULL }; switch (fork()) { case -1: @@ -117,6 +117,7 @@ static void master_exec(int fd) if (setsid() < 0) i_fatal("setsid() failed: %m"); + env_put("DOVECOT_INETD=1"); execv(SBINDIR"/dovecot", argv); i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", SBINDIR"/dovecot"); diff --git a/src/master/mail-process.c b/src/master/mail-process.c index 6207ccfc0c..72813220e9 100644 --- a/src/master/mail-process.c +++ b/src/master/mail-process.c @@ -75,10 +75,9 @@ static int validate_chroot(struct settings *set, const char *dir) } static const struct var_expand_table * -get_var_expand_table(enum process_type process_type, +get_var_expand_table(const char *protocol, const char *user, const char *home, - const struct ip_addr *local_ip, - const struct ip_addr *remote_ip, pid_t pid) + const char *local_ip, const char *remote_ip, pid_t pid) { static struct var_expand_table static_tab[] = { { 'u', NULL }, @@ -100,10 +99,10 @@ get_var_expand_table(enum process_type process_type, tab[1].value = t_strcut(user, '@'); tab[2].value = strchr(user, '@'); if (tab[2].value != NULL) tab[2].value++; - tab[3].value = t_str_ucase(process_names[process_type]); + tab[3].value = t_str_ucase(protocol); tab[4].value = home; - tab[5].value = net_ip2addr(local_ip); - tab[6].value = net_ip2addr(remote_ip); + tab[5].value = local_ip; + tab[6].value = remote_ip; tab[7].value = dec2str(pid); return tab; @@ -180,6 +179,133 @@ env_put_namespace(struct namespace_settings *ns, const char *default_location, } } +static void +mail_process_set_environment(struct settings *set, const char *mail, + const struct var_expand_table *var_expand_table) +{ + 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)); + env_put(t_strdup_printf("MAILBOX_IDLE_CHECK_INTERVAL=%u", + set->mailbox_idle_check_interval)); + env_put(t_strconcat("CLIENT_WORKAROUNDS=", + set->client_workarounds, NULL)); + env_put(t_strdup_printf("MAIL_MAX_KEYWORD_LENGTH=%u", + set->mail_max_keyword_length)); + env_put(t_strdup_printf("IMAP_MAX_LINE_LENGTH=%u", + set->imap_max_line_length)); + env_put(t_strconcat("IMAP_CAPABILITY=", + set->imap_capability, NULL)); + + if (set->mail_save_crlf) + env_put("MAIL_SAVE_CRLF=1"); + if (set->mail_read_mmaped) + env_put("MAIL_READ_MMAPED=1"); + if (set->mmap_disable) + env_put("MMAP_DISABLE=1"); + if (set->mmap_no_write) + env_put("MMAP_NO_WRITE=1"); + if (set->fcntl_locks_disable) + env_put("FCNTL_LOCKS_DISABLE=1"); + if (set->maildir_stat_dirs) + env_put("MAILDIR_STAT_DIRS=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->mail_full_filesystem_access) + env_put("FULL_FILESYSTEM_ACCESS=1"); + if (set->pop3_mails_keep_recent) + env_put("POP3_MAILS_KEEP_RECENT=1"); + (void)umask(set->umask); + + env_put(t_strconcat("MBOX_READ_LOCKS=", set->mbox_read_locks, NULL)); + env_put(t_strconcat("MBOX_WRITE_LOCKS=", set->mbox_write_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->mail_use_modules && + set->mail_modules != NULL && *set->mail_modules != '\0') { + env_put(t_strconcat("MODULE_DIR=", + set->mail_modules, NULL)); + } + + /* 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. */ + if ((mail == NULL || *mail == '\0') && set->default_mail_env != NULL) + mail = expand_mail_env(set->default_mail_env, var_expand_table); + env_put(t_strconcat("MAIL=", mail, NULL)); + + if (set->server->namespaces != NULL) { + env_put_namespace(set->server->namespaces, + mail, var_expand_table); + } +} + +static void mail_process_exec_set(struct settings *set, const char *title) +{ + const char *executable, *p, *argv[4]; + int i; + + /* very simple argument splitting. */ + i = 0; + argv[i++] = executable = t_strcut(set->mail_executable, ' '); + argv[i] = strchr(set->mail_executable, ' '); + if (argv[i] != NULL) { + argv[i]++; + i++; + } + if (title[0] != '\0') + argv[i++] = title; + argv[i] = NULL; + + /* hide the path, it's ugly */ + p = strrchr(argv[0], '/'); + if (p != NULL) argv[0] = p+1; + + execv(executable, (char **) argv); +} + +void mail_process_exec(const char *protocol, const char *section) +{ + struct server_settings *server = settings_root; + const struct var_expand_table *var_expand_table; + struct settings *set; + + if (section != NULL) { + for (; server != NULL; server = server->next) { + if (strcmp(server->name, section) == 0) + break; + } + if (server == NULL) + i_fatal("Section not found: '%s'", section); + } + + if (strcmp(protocol, "imap") == 0) + set = server->imap; + else if (strcmp(protocol, "pop3") == 0) + set = server->pop3; + else + i_fatal("Unknown protocol: '%s'", protocol); + + var_expand_table = + get_var_expand_table(protocol, getenv("USER"), getenv("HOME"), + getenv("TCPLOCALIP"), + getenv("TCPREMOTEIP"), getpid()); + + mail_process_set_environment(set, getenv("MAIL"), var_expand_table); + mail_process_exec_set(set, ""); + + i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", + set->mail_executable); +} + int create_mail_process(struct login_group *group, int socket, const struct ip_addr *local_ip, const struct ip_addr *remote_ip, @@ -187,11 +313,9 @@ int create_mail_process(struct login_group *group, int socket, { struct settings *set = group->set; const struct var_expand_table *var_expand_table; - const char *argv[4]; const char *addr, *mail, *user, *chroot_dir, *home_dir, *full_home_dir; - const char *executable, *p; - struct log_io *log; char title[1024]; + struct log_io *log; string_t *str; pid_t pid; int i, err, ret, log_fd; @@ -231,8 +355,10 @@ int create_mail_process(struct login_group *group, int socket, } var_expand_table = - get_var_expand_table(group->process_type, user, home_dir, - local_ip, remote_ip, + get_var_expand_table(process_names[group->process_type], + user, home_dir, + net_ip2addr(local_ip), + net_ip2addr(remote_ip), pid != 0 ? pid : getpid()); str = t_str_new(128); @@ -271,7 +397,7 @@ int create_mail_process(struct login_group *group, int socket, set->first_valid_gid, set->last_valid_gid, set->mail_extra_groups); - restrict_process_size(group->set->mail_process_size, (unsigned int)-1); + restrict_process_size(set->mail_process_size, (unsigned int)-1); if (*home_dir == '\0') ret = -1; @@ -302,73 +428,10 @@ int create_mail_process(struct login_group *group, int socket, i_fatal("chdir(/tmp) failed: %m"); } + mail_process_set_environment(set, mail, var_expand_table); + env_put("LOGGED_IN=1"); env_put(t_strconcat("HOME=", home_dir, 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)); - env_put(t_strdup_printf("MAILBOX_IDLE_CHECK_INTERVAL=%u", - set->mailbox_idle_check_interval)); - env_put(t_strconcat("CLIENT_WORKAROUNDS=", - set->client_workarounds, NULL)); - env_put(t_strdup_printf("MAIL_MAX_KEYWORD_LENGTH=%u", - set->mail_max_keyword_length)); - env_put(t_strdup_printf("IMAP_MAX_LINE_LENGTH=%u", - set->imap_max_line_length)); - env_put(t_strconcat("IMAP_CAPABILITY=", - set->imap_capability, NULL)); - - if (set->mail_save_crlf) - env_put("MAIL_SAVE_CRLF=1"); - if (set->mail_read_mmaped) - env_put("MAIL_READ_MMAPED=1"); - if (set->mmap_disable) - env_put("MMAP_DISABLE=1"); - if (set->mmap_no_write) - env_put("MMAP_NO_WRITE=1"); - if (set->fcntl_locks_disable) - env_put("FCNTL_LOCKS_DISABLE=1"); - if (set->maildir_stat_dirs) - env_put("MAILDIR_STAT_DIRS=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->mail_full_filesystem_access) - env_put("FULL_FILESYSTEM_ACCESS=1"); - if (set->pop3_mails_keep_recent) - env_put("POP3_MAILS_KEEP_RECENT=1"); - (void)umask(set->umask); - - env_put(t_strconcat("MBOX_READ_LOCKS=", set->mbox_read_locks, NULL)); - env_put(t_strconcat("MBOX_WRITE_LOCKS=", set->mbox_write_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 (group->set->mail_use_modules && - group->set->mail_modules != NULL && - *group->set->mail_modules != '\0') { - env_put(t_strconcat("MODULE_DIR=", - group->set->mail_modules, NULL)); - } - - /* 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. */ - if (*mail == '\0' && set->default_mail_env != NULL) - mail = expand_mail_env(set->default_mail_env, var_expand_table); - - if (set->server->namespaces != NULL) { - env_put_namespace(set->server->namespaces, - mail, var_expand_table); - } - - env_put(t_strconcat("MAIL=", mail, NULL)); env_put(t_strconcat("USER=", data + reply->virtual_user_idx, NULL)); addr = net_ip2addr(remote_ip); @@ -391,23 +454,7 @@ int create_mail_process(struct login_group *group, int socket, if (set->mail_drop_priv_before_exec) restrict_access_by_env(TRUE); - /* very simple argument splitting. */ - i = 0; - argv[i++] = executable = t_strcut(group->set->mail_executable, ' '); - argv[i] = strchr(group->set->mail_executable, ' '); - if (argv[i] != NULL) { - argv[i]++; - i++; - } - if (title[0] != '\0') - argv[i++] = title; - argv[i] = NULL; - - /* hide the path, it's ugly */ - p = strrchr(argv[0], '/'); - if (p != NULL) argv[0] = p+1; - - execv(executable, (char **) argv); + mail_process_exec_set(set, title); err = errno; for (i = 0; i < 3; i++) @@ -415,7 +462,7 @@ int create_mail_process(struct login_group *group, int socket, errno = err; i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", - group->set->mail_executable); + set->mail_executable); /* not reached */ return FALSE; diff --git a/src/master/mail-process.h b/src/master/mail-process.h index 3f6a61b94f..93af306fac 100644 --- a/src/master/mail-process.h +++ b/src/master/mail-process.h @@ -4,6 +4,8 @@ struct login_group; struct auth_master_reply; +void mail_process_exec(const char *protocol, const char *section); + int create_mail_process(struct login_group *group, int socket, const struct ip_addr *local_ip, const struct ip_addr *remote_ip, diff --git a/src/master/main.c b/src/master/main.c index 6fe66ffb07..d3faaf0226 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -99,7 +99,7 @@ static void settings_reload(void) login_processes_destroy_all(); auth_processes_destroy_all(); - if (!master_settings_read(configfile)) + if (!master_settings_read(configfile, FALSE)) i_warning("Invalid configuration, keeping old one"); else { listen_fds_close(old_set); @@ -482,9 +482,13 @@ static void print_help(void) int main(int argc, char *argv[]) { /* parse arguments */ + const char *exec_protocol = NULL, *exec_section = NULL; int foreground = FALSE; int i; +#ifdef DEBUG + gdb = getenv("GDB") != NULL; +#endif lib_init(); master_uid = geteuid(); @@ -498,13 +502,14 @@ int main(int argc, char *argv[]) i++; if (i == argc) i_fatal("Missing config file argument"); configfile = argv[i]; - } else if (strcmp(argv[i], "--inetd") == 0) { - /* starting through inetd. */ - inetd_login_fd = dup(0); - if (inetd_login_fd == -1) - i_fatal("dup(0) failed: %m"); - fd_close_on_exec(inetd_login_fd, TRUE); - foreground = TRUE; + } else if (strcmp(argv[i], "--exec-mail") == 0) { + /* [] + read configuration and execute mail process */ + i++; + if (i == argc) i_fatal("Missing protocol argument"); + exec_protocol = argv[i]; + if (i+1 != argc) + exec_section = argv[i++]; } else if (strcmp(argv[i], "--version") == 0) { printf("%s\n", VERSION); return 0; @@ -514,18 +519,28 @@ int main(int argc, char *argv[]) } } + if (getenv("DOVECOT_INETD") != NULL) { + /* starting through inetd. */ + inetd_login_fd = dup(0); + if (inetd_login_fd == -1) + i_fatal("dup(0) failed: %m"); + fd_close_on_exec(inetd_login_fd, TRUE); + foreground = TRUE; + } + /* read and verify settings before forking */ master_settings_init(); - if (!master_settings_read(configfile)) + if (!master_settings_read(configfile, exec_protocol != NULL)) exit(FATAL_DEFAULT); - open_fds(); -#ifdef DEBUG - gdb = getenv("GDB") != NULL; -#endif - /* we don't need any environment */ + if (exec_protocol != NULL) + mail_process_exec(exec_protocol, exec_section); + + /* we don't need any environment anymore */ env_clean(); + open_fds(); + if (!foreground) daemonize(settings_root->defaults); diff --git a/src/master/master-settings.c b/src/master/master-settings.c index 47bc75e423..ea29566adf 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -908,7 +908,7 @@ static int parse_section(const char *type, const char *name, void *context, return FALSE; } -int master_settings_read(const char *path) +int master_settings_read(const char *path, int nochecks) { struct settings_parse_ctx ctx; struct server_settings *server, *prev; @@ -949,7 +949,7 @@ int master_settings_read(const char *path) if (!settings_is_active(server->imap)) server->imap = NULL; else { - if (!settings_verify(server->imap)) + if (!nochecks && !settings_verify(server->imap)) return FALSE; server->defaults = server->imap; } @@ -957,7 +957,7 @@ int master_settings_read(const char *path) if (!settings_is_active(server->pop3)) server->pop3 = NULL; else { - if (!settings_verify(server->pop3)) + if (!nochecks && !settings_verify(server->pop3)) return FALSE; if (server->defaults == NULL) server->defaults = server->pop3; @@ -976,14 +976,16 @@ int master_settings_read(const char *path) return FALSE; } - 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; + 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; } diff --git a/src/master/master-settings.h b/src/master/master-settings.h index 6907e16135..f639cee45a 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -171,7 +171,7 @@ struct server_settings { extern struct server_settings *settings_root; -int master_settings_read(const char *path); +int master_settings_read(const char *path, int nochecks); void master_settings_init(void); void master_settings_deinit(void);