Executing a sieve-extprograms pipe script as non-root
Hi,
Ultimately I'm trying to call procmail via a pipe "procmail"; in my Sieve
script on Dovecot 2.4.1. I have therefore created the respective wrapper script
in /usr/lib/dovecot/sieve-pipe/procmail, but I noted that the script is
apparently run as root. With some debug output in the wrapper script, I see:
# `id` output
uid=0(root) gid=1059(rhi) groups=1059(rhi),116(dovecot)
# `pstree -s -u $$`
systemd(1)---dovecot(1064)---lmtp(266577,rhi)---procmail(266706,root)---pstree(266711)
This Dovecot gets mail delivered via LMTP from another server. 1059 (rhi) is my
local user ID on the IMAP server both in /etc/passwd and in /etc/dovecot/users
(using auth-passwdfile.conf.ext in 10-auth.conf instead of auth-system.conf.ext),
since mail needs to be delivered and chown'ed correctly into Maildirs that
should be user-accessible. However I don't understand how the procmail
wrapper can be run as the root user rights when the LMTP process starting it is
running as my own user?!?
I'd like to prevent procmail from running as root as far as possible, so for
now I've been able to work around this by wrapping the procmail call into an
additional sudo -U $USER (after determining the user who owns the target
maildir), but I'd like to understand the problem a bit further and like to know
if this is really how calling sieve-extprograms is supposed to work – I'd have
expected that the external scripts are also run as my unprivileged user.
I'm running a fairly standard config on Debian stable (dovecot package version 1:2.4.1+dfsg1-6+deb13u2) with only minimal changes by enabling the passwdfile backend and some sieve plugins.
Thanks for any insights,
- Roland
-- Roland Hieber, Pengutronix e.K. | rhi@pengutronix.de | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
On 04/03/2026 14:14 EET Roland Hieber via dovecot <dovecot@dovecot.org> wrote:
Hi,
Ultimately I'm trying to call procmail via a
pipe "procmail";in my Sieve script on Dovecot 2.4.1. I have therefore created the respective wrapper script in /usr/lib/dovecot/sieve-pipe/procmail, but I noted that the script is apparently run as root. With some debug output in the wrapper script, I see:# `id` output uid=0(root) gid=1059(rhi) groups=1059(rhi),116(dovecot) # `pstree -s -u $$` systemd(1)---dovecot(1064)---lmtp(266577,rhi)---procmail(266706,root)---pstree(266711)This Dovecot gets mail delivered via LMTP from another server. 1059 (rhi) is my local user ID on the IMAP server both in /etc/passwd and in /etc/dovecot/users (using auth-passwdfile.conf.ext in 10-auth.conf instead of auth-system.conf.ext), since mail needs to be delivered and chown'ed correctly into Maildirs that should be user-accessible. However I don't understand how the
procmailwrapper can be run as the root user rights when the LMTP process starting it is running as my own user?!?I'd like to prevent procmail from running as root as far as possible, so for now I've been able to work around this by wrapping the procmail call into an additional
sudo -U $USER(after determining the user who owns the target maildir), but I'd like to understand the problem a bit further and like to know if this is really how calling sieve-extprograms is supposed to work – I'd have expected that the external scripts are also run as my unprivileged user.I'm running a fairly standard config on Debian stable (dovecot package version 1:2.4.1+dfsg1-6+deb13u2) with only minimal changes by enabling the passwdfile backend and some sieve plugins.
Thanks for any insights,
- Roland
--
Can you share your doveconf output? Also is procmail setuid binary?
Aki
On Wed, Mar 04, 2026 at 02:20:23PM +0200, Aki Tuomi wrote:
On 04/03/2026 14:14 EET Roland Hieber via dovecot <dovecot@dovecot.org> wrote:
Hi,
Ultimately I'm trying to call procmail via a
pipe "procmail";in my Sieve script on Dovecot 2.4.1. I have therefore created the respective wrapper script in /usr/lib/dovecot/sieve-pipe/procmail, but I noted that the script is apparently run as root. With some debug output in the wrapper script, I see:# `id` output uid=0(root) gid=1059(rhi) groups=1059(rhi),116(dovecot) # `pstree -s -u $$` systemd(1)---dovecot(1064)---lmtp(266577,rhi)---procmail(266706,root)---pstree(266711)This Dovecot gets mail delivered via LMTP from another server. 1059 (rhi) is my local user ID on the IMAP server both in /etc/passwd and in /etc/dovecot/users (using auth-passwdfile.conf.ext in 10-auth.conf instead of auth-system.conf.ext), since mail needs to be delivered and chown'ed correctly into Maildirs that should be user-accessible. However I don't understand how the
procmailwrapper can be run as the root user rights when the LMTP process starting it is running as my own user?!?I'd like to prevent procmail from running as root as far as possible, so for now I've been able to work around this by wrapping the procmail call into an additional
sudo -U $USER(after determining the user who owns the target maildir), but I'd like to understand the problem a bit further and like to know if this is really how calling sieve-extprograms is supposed to work – I'd have expected that the external scripts are also run as my unprivileged user.I'm running a fairly standard config on Debian stable (dovecot package version 1:2.4.1+dfsg1-6+deb13u2) with only minimal changes by enabling the passwdfile backend and some sieve plugins.
Thanks for any insights,
- Roland
--
Can you share your doveconf output? Also is procmail setuid binary?
/usr/bin/procmail is not setuid. Note that the procmail in the pstree output
above is really the wrapper script in /usr/lib/dovecot/sieve-pipe/procmail, not
/usr/bin/procmail.
doveconf output below. (The lmtp service listens on a Unix socket because there is an SSL endpoint in front of it which checks certificates and translates from TCP port 24 to the Unix socket.)
# 2.4.1-4 (7d8c0e5759): /etc/dovecot/dovecot.conf
# Pigeonhole version 2.4.1-4 (0a86619f)
# OS: Linux 6.12.73+deb13-amd64 x86_64 Debian 13.3
# Hostname: <redacted>
# 4 default setting changes since version 2.4.0
dovecot_config_version = 2.4.0
auth_mechanisms = plain login
auth_username_format = %{user|lower}
auth_verbose = yes
dovecot_storage_version = 2.4.0
fts_autoindex = yes
fts_autoindex_max_recent_msgs = 999
fts_search_add_missing = yes
lmtp_save_to_detail_mailbox = yes
mail_driver = maildir
mail_home = /srv/mail/%{user}
mail_inbox_path = INBOX
mail_path = %{home}/mail
mail_privileged_group = mail
protocols {
imap = yes
lmtp = yes
sieve = yes
}
sieve_extensions {
fileinto = yes
reject = yes
envelope = yes
encoded-character = yes
vacation = yes
subaddress = yes
comparator-i;ascii-numeric = yes
relational = yes
regex = yes
imap4flags = yes
copy = yes
include = yes
body = yes
variables = yes
enotify = yes
environment = yes
mailbox = yes
date = yes
index = yes
ihave = yes
duplicate = yes
mime = yes
foreverypart = yes
extracttext = yes
vnd.dovecot.debug = yes
vnd.dovecot.pipe = yes
editheader = yes
}
sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe
sieve_pipe_socket_dir = sieve-pipe
sieve_plugins {
sieve_extprograms = yes
}
sieve_trace_debug = yes
sieve_trace_level = matching
ssl = required
verbose_proctitle = yes
passdb passwd-file {
auth_username_format = %{user}
default_password_scheme = crypt
passwd_file_path = /etc/dovecot/users
}
userdb passwd-file {
auth_username_format = %{user}
passwd_file_path = /etc/dovecot/users
}
namespace inbox {
inbox = yes
separator = /
mailbox Drafts {
special_use = "\\Drafts"
}
mailbox Junk {
special_use = "\\Junk"
}
mailbox Trash {
special_use = "\\Trash"
}
mailbox Sent {
special_use = "\\Sent"
}
mailbox "Sent Messages" {
special_use = "\\Sent"
}
}
service imap-login {
inet_listener imap {
}
inet_listener imaps {
}
}
service pop3-login {
}
service submission-login {
}
service lmtp {
unix_listener lmtp {
mode = 0660
}
}
service imap {
}
service pop3 {
}
service submission {
}
service auth {
unix_listener auth-userdb {
}
}
service auth-worker {
}
service dict {
unix_listener dict {
}
}
ssl_server {
cert_file = /var/lib/dehydrated/certs/local/fullchain.pem
key_file = /var/lib/dehydrated/certs/local/privkey.pem
}
protocol lmtp {
mail_plugins {
sieve = yes
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
}
service managesieve {
}
service stats {
inet_listener http {
port = 9243
listen = 127.0.0.1 ::1
}
}
metric auth_success {
filter = (event=auth_request_finished AND success=yes)
}
sieve_script personal {
active_path = ~/.dovecot.sieve
driver = file
path = ~/sieve
}
-- Roland Hieber, Pengutronix e.K. | rhi@pengutronix.de | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Hello, have you put DROPPRIVS=yes in /etc/procmailrc
-- Adrian C. (anrxc) | anrxc..sysphere.org | PGP ID: D20A0618 PGP FP: 02A5 628A D8EE 2A93 996E 929F D5CB 31B7 D20A 0618
On 05/03/2026 01:00 EET rhi--- via dovecot <dovecot@dovecot.org> wrote:
Hello, have you put DROPPRIVS=yes in /etc/procmailrc
No. As I said above:
Note that the
procmailin the pstree output above is really the wrapper script in /usr/lib/dovecot/sieve-pipe/procmail, not /usr/bin/procmail.
I am very puzzled how it can even run as root.
Can you run dovecot with
log_debug=category=lmtp
and provide the resultant logs during delivery?
Aki
participants (4)
-
Adrian C.
-
Aki Tuomi
-
rhi@pengutronix.de
-
Roland Hieber