Sieve Extprograms plugin for Pigeonhole Relevant specifications ======================= doc/rfc/spec-bosch-sieve-extprograms.txt Introduction ============ Sieve (RFC 5228) is a highly extensible machine language specifically tailored for internet message filtering. For the Dovecot Secure IMAP server, Sieve support is provided by the Pigeonhole Sieve plugin. This package includes a plugin for Pigeonhole called "sieve_extprograms", which extends the Sieve filtering implementation with action commands for invoking a predefined set of external programs. Messages can be piped to or filtered through those programs and string data can be input to and retrieved from those programs. The Sieve language is explicitly designed to be powerful enough to be useful yet limited in order to allow for a safe server-side filtering system. Therefore, the base specification of the language makes it impossible for users to do anything more complex (and dangerous) than write simple mail filters. One of the consequences of this security-minded design is that users cannot execute external programs from their mail filter. Particularly for server-side filtering setups in which mail accounts have no corresponding system account, allowing the execution of arbitrary programs from the mail filter can be a significant security risk. However, such functionality can also be very useful, for instance to easily implement a custom action or external effect that Sieve normally cannot provide. The "sieve_extprograms" plugin provides an extension to the Sieve filtering language adding new action commands for invoking a predefined set of external programs. To mitigate the security concerns, the external programs cannot be chosen arbitrarily; the available programs are restricted through administrator configuration. This extension is specific to the Pigeonhole Sieve implementation for the Dovecot Secure IMAP server. It will therefore most likely not be supported by web interfaces or GUI-based Sieve editors. This extension is primarily meant for use in small setups or global scripts that are managed by the systems administrator. Implementation Status --------------------- The "vnd.dovecot.pipe", "vnd.dovecot.filter" and "vnd.dovecot.execute" Sieve language extensions introduced by this plugin are vendor-specific with draft status and their implementation for Pigeonhole is experimental, which means that the language extensions are still subject to change and that the current implementation is not thoroughly tested. Configuration ============= The plugin is activated by adding it to the sieve_plugins setting: sieve_plugins = sieve_extprograms This plugin registers the "vnd.dovecot.pipe", "vnd.dovecot.filter" and "vnd.dovecot.execute" extensions with the Sieve interpreter. However, these extensions are not enabled by default and thus need to be enabled explicitly. It is recommended to restrict the use of these extensions to global context by adding these to the "sieve_global_extensions" setting. If personal user scripts also need to directly access external programs, the extensions need to be added to the "sieve_extensions" setting. The commands introduced by the Sieve language extensions in this plugin can directly pipe a message or string data to an external program (typically a shell script) by forking a new process. Alternatively, these can connect to a unix socket behind which a Dovecot script service is listening to start the external program, e.g. to execute as a different user or for added security. The program name specified for the new Sieve "pipe", "filter" and "execute" commands is used to find the program or socket in a configured directory. Separate directories are specified for the sockets and the directly executed binaries. The socket directory is searched first. Since the use of "/" in program names is prohibited, it is not possible to build a hierarchical structure. Directly forked programs are executed with a limited set of environment variables: HOME, USER, HOST, SENDER, RECIPIENT and ORIG_RECIPIENT. Programs executed through the script-pipe socket service currently have no environment set at all. If a shell script is expected to read a message or string data, it must fully read the provided input until the data ends with EOF, otherwise the Sieve action invoking the program will fail. The action will also fail when the shell script returns a nonzero exit code. Standard output is available for returning a message (for the filter command) or string data (for the execute command) to the Sieve interpreter. Standard error is written to the LDA log file. The three extensions introduced by this plugin - "vnd.dovecot.pipe", "vnd.dovecot.filter" and "vnd.dovecot.pipe" - each have separate but similar configuration. The settings that specify a time period are specified in s(econds), unless followed by a d(ay), h(our) or m(inute) specifier character. The following configuration settings are used, for which "" in the setting name is replaced by either "pipe", "filter" or "execute" depending on which extension is being configured. sieve__socket_dir = Points to a directory relative to the Dovecot base_dir where the plugin looks for script service sockets. sieve__bin_dir = Points to a directory where the plugin looks for programs (shell scripts) to execute directly and pipe messages to. sieve__exec_timeout = 10s Configures the maximum execution time after which the program is forcibly terminated. sieve__input_eol = crlf Determines the end-of-line character sequence used for the data piped to external programs. The default is currently "crlf", which represents a sequence of the carriage return (CR) and line feed (LF) characters. This matches the Internet Message Format (RFC5322) and what Sieve itself uses as a line ending. Set this setting to "lf" to use a single LF character instead. Examples -------- Example 1: socket service for "pipe" and "execute" plugin { sieve = ~/.dovecot.sieve sieve_plugins = sieve_extprograms sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute # pipe sockets in /var/run/dovecot/sieve-pipe sieve_pipe_socket_dir = sieve-pipe # execute sockets in /var/run/dovecot/sieve-execute sieve_execute_socket_dir = sieve-execute } service sieve-pipe-script { # This script is executed for each service connection executable = script /usr/lib/dovecot/sieve-extprograms/sieve-pipe-action.sh # use some unprivileged user for execution user = dovenull # socket name is program-name in Sieve (without sieve-pipe/ prefix) unix_listener sieve-pipe/sieve-pipe-script { } } service sieve-execute-action { # This script is executed for each service connection executable = script /usr/lib/dovecot/sieve-extprograms/sieve-execute-action.sh # use some unprivileged user for execution user = dovenull # socket name is program-name in Sieve (without sieve-execute/ prefix) unix_listener sieve-execute/sieve-execute-action { } } Example 2: direct execution for "pipe" and "filter" plugin { sieve = ~/.dovecot.sieve sieve_plugins = sieve_extprograms sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.filter # This directory contains the scripts that are available for the pipe command. sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe # This directory contains the scripts that are available for the filter # command. sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter } Using ===== Refer to doc/rfc/spec-bosch-sieve-extprograms.txt for a specification of the Sieve language extensions.