From 03c8bfc7837769003678f2ac9afd52be9f1b3ed5 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sat, 3 Jul 2010 14:21:38 +0200 Subject: [PATCH] ManageSieve: enabled dynamic capability inference. --- m4/dovecot.m4 | 2 +- src/managesieve-login/Makefile.am | 6 +- .../managesieve-login-settings-plugin.c | 204 ++++++++++++++++++ .../managesieve-login-settings-plugin.h | 12 ++ .../managesieve-login-settings.c | 192 ----------------- .../managesieve-login-settings.h | 1 + 6 files changed, 222 insertions(+), 195 deletions(-) create mode 100644 src/managesieve-login/managesieve-login-settings-plugin.c create mode 100644 src/managesieve-login/managesieve-login-settings-plugin.h diff --git a/m4/dovecot.m4 b/m4/dovecot.m4 index b277095dd..77972b6ba 100644 --- a/m4/dovecot.m4 +++ b/m4/dovecot.m4 @@ -56,7 +56,7 @@ AC_DEFUN([DC_DOVECOT],[ AX_SUBST_L([DOVECOT_CFLAGS], [DOVECOT_LIBS], [DOVECOT_SSL_LIBS]) AX_SUBST_L([LIBDOVECOT], [LIBDOVECOT_LOGIN], [LIBDOVECOT_SQL], [LIBDOVECOT_LDA], [LIBDOVECOT_STORAGE]) AX_SUBST_L([LIBDOVECOT_DEPS], [LIBDOVECOT_LOGIN_DEPS], [LIBDOVECOT_SQL_DEPS], [LIBDOVECOT_LDA_DEPS], [LIBDOVECOT_STORAGE_DEPS]) - AX_SUBST_L([LIBDOVECOT_INCLUDE], [LIBDOVECOT_LDA_INCLUDE], [LIBDOVECOT_SERVICE_INCLUDE], [LIBDOVECOT_STORAGE_INCLUDE], [LIBDOVECOT_LOGIN_INCLUDE]) + AX_SUBST_L([LIBDOVECOT_INCLUDE], [LIBDOVECOT_LDA_INCLUDE], [LIBDOVECOT_SERVICE_INCLUDE], [LIBDOVECOT_STORAGE_INCLUDE], [LIBDOVECOT_LOGIN_INCLUDE], [LIBDOVECOT_CONFIG_INCLUDE]) DC_PLUGIN_DEPS ]) diff --git a/src/managesieve-login/Makefile.am b/src/managesieve-login/Makefile.am index c5f29aa09..777cfb0fe 100644 --- a/src/managesieve-login/Makefile.am +++ b/src/managesieve-login/Makefile.am @@ -15,8 +15,9 @@ settings_LTLIBRARIES = \ libmanagesieve_login_settings.la libmanagesieve_login_settings_la_SOURCES = \ - managesieve-login-settings.c -libmanagesieve_login_settings_la_CFLAGS = $(AM_CFLAGS) -D_CONFIG_PLUGIN -DPKG_LIBEXECDIR=\""$(dovecot_pkglibexecdir)"\" + managesieve-login-settings-plugin.c +libmanagesieve_login_settings_la_CFLAGS = \ + $(AM_CFLAGS) $(LIBDOVECOT_CONFIG_INCLUDE) -DPKG_LIBEXECDIR=\""$(dovecot_pkglibexecdir)"\" libs = \ $(top_srcdir)/src/lib-managesieve/libmanagesieve.a @@ -34,4 +35,5 @@ noinst_HEADERS = \ client.h \ client-authenticate.h \ managesieve-login-settings.h \ + managesieve-login-settings-plugin.h \ managesieve-proxy.h diff --git a/src/managesieve-login/managesieve-login-settings-plugin.c b/src/managesieve-login/managesieve-login-settings-plugin.c new file mode 100644 index 000000000..274e88a75 --- /dev/null +++ b/src/managesieve-login/managesieve-login-settings-plugin.c @@ -0,0 +1,204 @@ +/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "buffer.h" +#include "env-util.h" +#include "fd-close-on-exec.h" +#include "execv-const.h" +#include "settings-parser.h" +#include "config-parser-private.h" +#include "managesieve-login-settings-plugin.h" + +#include <stddef.h> +#include <unistd.h> +#include <sys/wait.h> +#include <sysexits.h> + +typedef enum { CAP_SIEVE, CAP_NOTIFY } capability_type_t; + +static char *capability_sieve = NULL; +static char *capability_notify = NULL; + +static void (*next_hook_config_parser_begin)(struct config_parser_context *ctx) = NULL; + +static void managesieve_login_config_parser_begin(struct config_parser_context *ctx); + +void managesieve_login_settings_init(struct module *module ATTR_UNUSED) +{ + next_hook_config_parser_begin = hook_config_parser_begin; + hook_config_parser_begin = managesieve_login_config_parser_begin; +} + +void managesieve_login_settings_deinit(void) +{ + hook_config_parser_begin = next_hook_config_parser_begin; + + if ( capability_sieve != NULL ) + i_free(capability_sieve); + + if ( capability_notify != NULL ) + i_free(capability_notify); +} + +static void capability_store(capability_type_t cap_type, const char *value) +{ + switch ( cap_type ) { + case CAP_SIEVE: + capability_sieve = i_strdup(value); + break; + case CAP_NOTIFY: + capability_notify = i_strdup(value); + break; + } +} + +static void capability_parse(const char *cap_string) +{ + capability_type_t cap_type = CAP_SIEVE; + const char *p = cap_string; + string_t *part = t_str_new(256); + + if ( cap_string == NULL || *cap_string == '\0' ) { + i_warning("managesieve-login: capability string is empty."); + return; + } + + while ( *p != '\0' ) { + if ( *p == '\\' ) { + p++; + if ( *p != '\0' ) { + str_append_c(part, *p); + p++; + } else break; + } else if ( *p == ':' ) { + if ( strcasecmp(str_c(part), "SIEVE") == 0 ) + cap_type = CAP_SIEVE; + else if ( strcasecmp(str_c(part), "NOTIFY") == 0 ) + cap_type = CAP_NOTIFY; + else + i_warning("managesieve-login: unknown capability '%s' listed in " + "capability string (ignored).", str_c(part)); + str_truncate(part, 0); + } else if ( *p == ',' ) { + capability_store(cap_type, str_c(part)); + str_truncate(part, 0); + } else { + /* Append character, but omit leading spaces */ + if ( str_len(part) > 0 || *p != ' ' ) + str_append_c(part, *p); + } + p++; + } + + if ( str_len(part) > 0 ) { + capability_store(cap_type, str_c(part)); + } +} + +static bool capability_dump(void) +{ + char buf[4096]; + int fd[2], status; + ssize_t ret; + unsigned int pos; + pid_t pid; + + if ( pipe(fd) < 0 ) { + i_error("managesieve-login: dump-capability pipe() failed: %m"); + return FALSE; + } + fd_close_on_exec(fd[0], TRUE); + fd_close_on_exec(fd[1], TRUE); + + if ( (pid = fork()) == (pid_t)-1 ) { + (void)close(fd[0]); (void)close(fd[1]); + i_error("managesieve-login: dump-capability fork() failed: %m"); + return FALSE; + } + + if ( pid == 0 ) { + const char *argv[2]; + + /* Child */ + (void)close(fd[0]); + + if (dup2(fd[1], STDOUT_FILENO) < 0) + i_fatal("managesieve-login: dump-capability dup2() failed: %m"); + + env_put("DUMP_CAPABILITY=1"); + + argv[0] = PKG_LIBEXECDIR"/managesieve"; /* BAD */ + argv[1] = NULL; + execv_const(argv[0], argv); + + i_fatal("managesieve-login: dump-capability execv(%s) failed: %m", argv[0]); + } + + (void)close(fd[1]); + + alarm(5); + if (wait(&status) == -1) { + i_error("managesieve-login: dump-capability failed: process %d got stuck", + (int)pid); + return FALSE; + } + alarm(0); + + if (status != 0) { + (void)close(fd[0]); + if (WIFSIGNALED(status)) { + i_error("managesieve-login: dump-capability process " + "killed with signal %d", WTERMSIG(status)); + } else { + i_error("managesieve-login: dump-capability process returned %d", + WIFEXITED(status) ? WEXITSTATUS(status) : status); + } + return FALSE; + } + + pos = 0; + while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0) + pos += ret; + + if (ret < 0) { + i_error("managesieve-login: read(dump-capability process) failed: %m"); + (void)close(fd[0]); + return FALSE; + } + (void)close(fd[0]); + + if (pos == 0 || buf[pos-1] != '\n') { + i_error("managesieve-login: dump-capability: Couldn't read capability " + "(got %u bytes)", pos); + return FALSE; + } + buf[pos-1] = '\0'; + + capability_parse(buf); + + return TRUE; +} + +static void managesieve_login_config_set +(struct config_parser_context *ctx, const char *key, const char *value) +{ + config_apply_line(ctx, key, + t_strdup_printf("service/managesieve-login/%s=%s", key, value), NULL); +} + +static void managesieve_login_config_parser_begin(struct config_parser_context *ctx) +{ + if ( capability_sieve == NULL ) { + if ( !capability_dump() ) { + capability_sieve = ""; + } + } + + if ( capability_sieve != NULL ) + managesieve_login_config_set(ctx, "managesieve_sieve_capability", capability_sieve); + + if ( capability_notify != NULL ) + managesieve_login_config_set(ctx, "managesieve_notify_capability", capability_notify); +} diff --git a/src/managesieve-login/managesieve-login-settings-plugin.h b/src/managesieve-login/managesieve-login-settings-plugin.h new file mode 100644 index 000000000..be152ce0e --- /dev/null +++ b/src/managesieve-login/managesieve-login-settings-plugin.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file + */ + +#ifndef __MANAGESIEVE_LOGIN_SETTINGS_PLUGIN_H +#define __MANAGESIEVE_LOGIN_SETTINGS_PLUGIN_H + +#include "lib.h" + +void managesieve_login_settings_init(struct module *module); +void managesieve_login_settings_deinit(void); + +#endif /* __MANAGESIEVE_LOGIN_SETTINGS_PLUGIN_H */ diff --git a/src/managesieve-login/managesieve-login-settings.c b/src/managesieve-login/managesieve-login-settings.c index 06ad89a70..f00ee8af1 100644 --- a/src/managesieve-login/managesieve-login-settings.c +++ b/src/managesieve-login/managesieve-login-settings.c @@ -18,10 +18,6 @@ #include <sysexits.h> /* <settings checks> */ -#ifdef _CONFIG_PLUGIN -static bool managesieve_login_settings_verify - (void *_set, pool_t pool, const char **error_r); -#endif static struct inet_listener_settings managesieve_login_inet_listeners_array[] = { { "sieve", "", 4190, FALSE }, @@ -94,11 +90,6 @@ static const struct setting_parser_info managesieve_login_setting_parser_info = .parent_offset = (size_t)-1, .parent = NULL, - /* Only compiled in the doveconf plugin */ -#ifdef _CONFIG_PLUGIN -// .check_func = managesieve_login_settings_verify, -#endif - .dependencies = managesieve_login_setting_dependencies }; @@ -108,186 +99,3 @@ const struct setting_parser_info *managesieve_login_settings_set_roots[] = { NULL }; -/* - * Dynamic ManageSieve capability determination - * Only compiled in the doveconf plugin - */ - -#ifdef _CONFIG_PLUGIN - -typedef enum { CAP_SIEVE, CAP_NOTIFY } capability_type_t; - -static char *capability_sieve = NULL; -static char *capability_notify = NULL; - -void managesieve_login_settings_deinit(void) -{ - if ( capability_sieve != NULL ) - i_free(capability_sieve); - - if ( capability_notify != NULL ) - i_free(capability_notify); -} - -static void capability_store(capability_type_t cap_type, const char *value) -{ - switch ( cap_type ) { - case CAP_SIEVE: - capability_sieve = i_strdup(value); - break; - case CAP_NOTIFY: - capability_notify = i_strdup(value); - break; - } -} - -static void capability_parse(const char *cap_string) -{ - capability_type_t cap_type = CAP_SIEVE; - const char *p = cap_string; - string_t *part = t_str_new(256); - - if ( cap_string == NULL || *cap_string == '\0' ) { - i_warning("managesieve-login: capability string is empty."); - return; - } - - while ( *p != '\0' ) { - if ( *p == '\\' ) { - p++; - if ( *p != '\0' ) { - str_append_c(part, *p); - p++; - } else break; - } else if ( *p == ':' ) { - if ( strcasecmp(str_c(part), "SIEVE") == 0 ) - cap_type = CAP_SIEVE; - else if ( strcasecmp(str_c(part), "NOTIFY") == 0 ) - cap_type = CAP_NOTIFY; - else - i_warning("managesieve-login: unknown capability '%s' listed in " - "capability string (ignored).", str_c(part)); - str_truncate(part, 0); - } else if ( *p == ',' ) { - capability_store(cap_type, str_c(part)); - str_truncate(part, 0); - } else { - /* Append character, but omit leading spaces */ - if ( str_len(part) > 0 || *p != ' ' ) - str_append_c(part, *p); - } - p++; - } - - if ( str_len(part) > 0 ) { - capability_store(cap_type, str_c(part)); - } -} - -static bool capability_dump(void) -{ - char buf[4096]; - int fd[2], status; - ssize_t ret; - unsigned int pos; - pid_t pid; - - if ( pipe(fd) < 0 ) { - i_error("managesieve-login: dump-capability pipe() failed: %m"); - return FALSE; - } - fd_close_on_exec(fd[0], TRUE); - fd_close_on_exec(fd[1], TRUE); - - if ( (pid = fork()) == (pid_t)-1 ) { - (void)close(fd[0]); (void)close(fd[1]); - i_error("managesieve-login: dump-capability fork() failed: %m"); - return FALSE; - } - - if ( pid == 0 ) { - const char *argv[2]; - - /* Child */ - (void)close(fd[0]); - - if (dup2(fd[1], STDOUT_FILENO) < 0) - i_fatal("managesieve-login: dump-capability dup2() failed: %m"); - - env_put("DUMP_CAPABILITY=1"); - - argv[0] = PKG_LIBEXECDIR"/managesieve"; /* BAD */ - argv[1] = NULL; - execv_const(argv[0], argv); - - i_fatal("managesieve-login: dump-capability execv(%s) failed: %m", argv[0]); - } - - (void)close(fd[1]); - - alarm(5); - if (wait(&status) == -1) { - i_error("managesieve-login: dump-capability failed: process %d got stuck", - (int)pid); - return FALSE; - } - alarm(0); - - if (status != 0) { - (void)close(fd[0]); - if (WIFSIGNALED(status)) { - i_error("managesieve-login: dump-capability process " - "killed with signal %d", WTERMSIG(status)); - } else { - i_error("managesieve-login: dump-capability process returned %d", - WIFEXITED(status) ? WEXITSTATUS(status) : status); - } - return FALSE; - } - - pos = 0; - while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0) - pos += ret; - - if (ret < 0) { - i_error("managesieve-login: read(dump-capability process) failed: %m"); - (void)close(fd[0]); - return FALSE; - } - (void)close(fd[0]); - - if (pos == 0 || buf[pos-1] != '\n') { - i_error("managesieve-login: dump-capability: Couldn't read capability " - "(got %u bytes)", pos); - return FALSE; - } - buf[pos-1] = '\0'; - - capability_parse(buf); - - return TRUE; -} - -/* <settings checks> */ -static bool managesieve_login_settings_verify -(void *_set, pool_t pool ATTR_UNUSED, const char **error_r ATTR_UNUSED) -{ - struct managesieve_login_settings *set = _set; - - if ( capability_sieve == NULL ) { - if ( !capability_dump() ) { - capability_sieve = ""; - } - } - - if ( *set->managesieve_sieve_capability == '\0' && capability_sieve != NULL ) - set->managesieve_sieve_capability = capability_sieve; - - if ( *set->managesieve_notify_capability == '\0' && capability_notify != NULL ) - set->managesieve_notify_capability = capability_notify; - - return TRUE; -} -/* </settings checks> */ - -#endif /* _CONFIG_PLUGIN */ diff --git a/src/managesieve-login/managesieve-login-settings.h b/src/managesieve-login/managesieve-login-settings.h index 2d35cd9f4..5395ba915 100644 --- a/src/managesieve-login/managesieve-login-settings.h +++ b/src/managesieve-login/managesieve-login-settings.h @@ -13,6 +13,7 @@ struct managesieve_login_settings { extern const struct setting_parser_info *managesieve_login_settings_set_roots[]; #ifdef _CONFIG_PLUGIN +void managesieve_login_settings_init(void); void managesieve_login_settings_deinit(void); #endif -- GitLab