Hi,

I try to migrate an old fashioned mailsystem to Debian 9.7 / dovecot 2.2.7. I "have" to cope with mbox for now. I try to get rid of Sun OS 5.9 sendmail before mbox to mdbox migration (I'm fine if you laugh loudly ^^). Intended setup : 2 VM with exim (smtp in, smtp out roughly), 3 VM with dovecot (mbox, maildir, testbed), 1 VM with IMAP proxy and LMTP proxy.

doveconf -n is at end of this mail. My test case is :

root@wagram:~# swaks --to tstifi04 --server imap --protocol lmtp --header-X-Spam-Status yes
root@wagram:~#
(imap VM LMTP proxies to telegraphe5 VM in this test)

mbox folders are in users homedir, no generic "vmail" unix account. Real posixAccounts in LDAP, NFS root_squashed.

sieve "fileinto "Junk" call goes wrong :

Feb  6 17:56:03 telegraphe5 dovecot: lmtp(tstifi04): Error: PytSHqIRW1x2dgAA+Fldtw: sieve: msgid=unspecified: failed to store into mailbox 'Junk': Read-only mbox
straced : https://pastebin.com/A53hDYnS

I may miss some configuration options... but I get stuck. I get to IRC and it seems that there is no simple things to circumvent. I tried to read some code path too.

https://wiki.dovecot.org/LMTP states :

Security

Unfortunately LMTP process currently needs to run as root, and only temporarily drop privileges to users. Otherwise it couldn't handle mail deliveries to more than a single user with different UID. If you're using only a single global UID/GID, you can improve security by running lmtp processes as that user:
service lmtp {
  user = vmail
}
lmtp run as root, drop temporarily privileges. The point, IHMO, is lmtp calls sieve code paths, that call some mbox saving function, that calls libc/syscall access(). And this explicitly not consider effective uid/gid.

From strace (more in pastebin) :

[pid 30326] geteuid()                   = 0
[pid 30326] setresuid(-1, 20609, -1)    = 0
[pid 30326] geteuid()                   = 20609
[pid 30326] access("/home/tstifi04/mail-imap/Junk", R_OK|W_OK) = -1 EACCES (Permission denied)

From man access

       The check is done using the calling process's real UID and GID, rather than the effective IDs as  is  done  when  actually
       attempting  an  operation  (e.g., open(2)) on the file.  Similarly, for the root user, the check uses the set of permitted
       capabilities rather than the set of effective capabilities; and for non-root users, the check uses an empty set  of  capa-
       bilities.
I think that the process has effectively sufficient permissions to write into the root_squashed file, and infortunately access() check another thing.

In dovecot sources, src/lib/eacces-error.c is aware of those "problems" with access(), but I think that mbox and maybe other storage backends don't use this for main codepath (like save a mail), but "only" for smart log messages in some cases.

I may gone wrong while seeking about it. Do you see a configuration that can use root squashed mboxes and LMTP ?

Should test_access() variant could be used as access() replacement ?
There is eaccess() and euidaccess() too but may be not portable enough (_GNU_SOURCE only).

Regards,
Ludovic


telegraphe5:/dev/shm# mount | grep tstifi04
cifs1:/homeeleves/tstifi/tstifi04 on /home/tstifi04 type nfs (rw,nosuid,nodev,relatime,vers=3,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=172.16.2.29,mountvers=3,mountport=635,mountproto=udp,local_lock=none,addr=172.16.2.29)

telegraphe5:/dev/shm# dovecot -n
# 2.2.27 (c0f36b0): /etc/dovecot/dovecot.conf
# Pigeonhole version 0.4.16 (fed8554)
# OS: Linux 4.9.0-8-amd64 x86_64 Debian 9.7 
auth_debug = yes
auth_verbose = yes
default_client_limit = 10240
default_process_limit = 2048
lda_mailbox_autocreate = yes
lda_mailbox_autosubscribe = yes
mail_debug = yes
mail_fsync = always
mail_location = mbox:~/mail-imap:INBOX=/var/mail/mailbox/%u:INDEX=/var/dovecot-indexes/%u
mail_nfs_storage = yes
mail_plugins = quota
managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext
mbox_write_locks = fcntl
mmap_disable = yes
namespace inbox {
  inbox = yes
  location = 
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Sent {
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
  mailbox Trash {
    special_use = \Trash
  }
  prefix = 
}
passdb {
  args = /etc/dovecot/dovecot-ldap.conf.ext
  driver = ldap
}
plugin {
  mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename
  mail_log_fields = uid box msgid size
  quota = count:Quota mail global
  quota_rule = *:storage=100M
  quota_rule2 = Trash:storage=+100M
  quota_vsizes = yes
  quota_warning = storage=95%% quota-warning 95 %u
  quota_warning2 = storage=80%% quota-warning 80 %u
  sieve = file:/var/mail/mailconf/%1u/%u/sieve;active=/var/mail/mailconf/%1u/%u/.dovecot.sieve
  sieve_after = /var/mail/mailconf/global/sieve/after.d/
  sieve_before = /var/mail/mailconf/global/sieve/before.d/
  sieve_global = /var/mail/mailconf/global/sieve
  sieve_vacation_dont_check_recipient = yes
}
protocols = " imap lmtp sieve sieve"
service anvil {
  unix_listener anvil-auth-penalty {
    mode = 00
  }
}
service imap-login {
  inet_listener imap {
    port = 0
  }
}
service lmtp {
  inet_listener lmtp {
    port = 24
  }
}
service managesieve {
  process_limit = 16
}
service quota-warning {
  executable = script /usr/local/bin/quota-warning.sh
  unix_listener quota-warning {
    mode = 0666
  }
  user = root
}
ssl = required
ssl_cert = </etc/ssl/local_certs/telegraphe5_cert.pem
ssl_key =  # hidden, use -P to show it
syslog_facility = local0
userdb {
  args = /etc/dovecot/dovecot-ldap.conf.ext
  driver = ldap
}
verbose_proctitle = yes
protocol lmtp {
  mail_plugins = quota sieve
}
protocol imap {
  mail_max_userip_connections = 20
  mail_plugins = quota imap_quota
}

telegraphe5:/dev/shm# grep -vE '^(#|$)' /etc/dovecot/dovecot-ldap.conf.ext
uris = ldaps://ldap-test.mines-albi.fr
tls_require_cert = hard
auth_bind = yes
base = ou=People,dc=enstimac,dc=fr
user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid,\
  dcMailQuota=quota_rule=*:bytes=%{ldap:dcMailQuota}M
user_filter = (&(objectClass=posixAccount)(|(uid=%n)(mail=%n@mines-albi.fr)))
iterate_attrs = uid=user
iterate_filter = (objectClass=posixAccount)


telegraphe5:/dev/shm# ls -l /var/mail/mailconf/global/sieve/before.d/
total 0

telegraphe5:/dev/shm# ls -al /var/mail/mailconf/t/tstifi04/
total 44
drwx------   3 tstifi04 ifie2012  4096 févr.  5 10:46 .
drwxrwxrwt 169 root     root     16384 janv.  5 18:48 ..
lrwxrwxrwx   1 tstifi04 ifie2012    25 janv. 31 17:50 .dovecot.sieve -> sieve/rainloop.user.sieve
-rw-------   1 tstifi04 ifie2012  1520 févr.  5 13:22 .dovecot.sieve.log
-rw-------   1 tstifi04 ifie2012 10336 févr.  5 10:46 .dovecot.sieve.log.0
-rw-------   1 tstifi04 ifie2012   172 janv. 31 17:56 .dovecot.svbin
drwx------   3 tstifi04 ifie2012  4096 janv. 31 17:50 sieve
telegraphe5:/dev/shm# ls -al /var/mail/mailconf/t/tstifi04/sieve/rainloop.user.sieve 
-rw------- 1 tstifi04 ifie2012 102 janv. 31 17:50 /var/mail/mailconf/t/tstifi04/sieve/rainloop.user.sieve
telegraphe5:/dev/shm# cat /var/mail/mailconf/t/tstifi04/sieve/rainloop.user.sieve 

# This is RainLoop Webmail sieve script.
# Please don't change anything here.
# RAINLOOP:SIEVE

telegraphe5:/dev/shm# 


telegraphe5:/dev/shm# cat /var/mail/mailconf/global/sieve/after.d/spam-into-junk.sieve 
require ["fileinto"];

if header :is "X-Spam-Status" "Yes" {
        fileinto "Junk";
  stop;
}