<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Hi,</p>
    <p>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.</p>
    <p>doveconf -n is at end of this mail. My test case is :<br>
    </p>
    <pre>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)
</pre>
    <p>mbox folders are in users homedir, no generic "vmail" unix
      account. Real posixAccounts in LDAP, NFS root_squashed.</p>
    <p>sieve "fileinto "Junk" call goes wrong :</p>
    <p>
      <blockquote type="cite">Feb  6 17:56:03 telegraphe5 dovecot:
        lmtp(tstifi04): Error: PytSHqIRW1x2dgAA+Fldtw: sieve:
        msgid=unspecified: failed to store into mailbox 'Junk':
        Read-only mbox</blockquote>
      straced : <a moz-do-not-send="true"
        href="https://pastebin.com/A53hDYnS">https://pastebin.com/A53hDYnS</a></p>
    <p>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.<br>
    </p>
    <p><a moz-do-not-send="true" href="https://wiki.dovecot.org/LMTP">https://wiki.dovecot.org/LMTP</a>
      states :</p>
    <p>
      <blockquote type="cite">
        <h2 id="Security">Security</h2>
        <span class="anchor" id="line-37"></span><span class="anchor"
          id="line-38"></span>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: <br>
        <pre>service lmtp {
<span class="anchor" id="line-2-1"></span>  user = vmail
<span class="anchor" id="line-3-1"></span>}</pre>
      </blockquote>
      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.</p>
    <p>From strace (more in pastebin) :</p>
    <div class="de1">
      <blockquote type="cite">[pid 30326] geteuid()                   =
        0<br>
        [pid 30326] setresuid(-1, 20609, -1)    = 0<br>
        [pid 30326] geteuid()                   = 20609<br>
        [pid 30326] access("/home/tstifi04/mail-imap/Junk", R_OK|W_OK) =
        -1 EACCES (Permission denied)</blockquote>
    </div>
    <p>From man access<br>
    </p>
    <p>
      <blockquote type="cite">       The check is done using the calling
        process's real UID and GID, rather than the effective IDs as 
        is  done  when  actually<br>
               attempting  an  operation  (e.g., open(2)) on the file. 
        Similarly, for the root user, the check uses the set of
        permitted<br>
               capabilities rather than the set of effective
        capabilities; and for non-root users, the check uses an empty
        set  of  capa-<br>
               bilities.<br>
      </blockquote>
      I think that the process has effectively sufficient permissions to
      write into the root_squashed file, and infortunately access()
      check another thing.</p>
    <p>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.</p>
    <p>I may gone wrong while seeking about it. Do you see a
      configuration that can use root squashed mboxes and LMTP ?</p>
    <p> Should test_access() variant could be used as access()
      replacement ?<br>
      There is eaccess() and euidaccess() too but may be not portable
      enough (_GNU_SOURCE only).<br>
    </p>
    <p>Regards,<br>
      Ludovic<br>
    </p>
    <p><br>
    </p>
    <pre>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 = <a class="moz-txt-link-freetext" href="file:/var/mail/mailconf/%1u/%u/sieve;active=/var/mail/mailconf/%1u/%u/.dovecot.sieve">file:/var/mail/mailconf/%1u/%u/sieve;active=/var/mail/mailconf/%1u/%u/.dovecot.sieve</a>
  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 = <a class="moz-txt-link-freetext" href="ldaps://ldap-test.mines-albi.fr">ldaps://ldap-test.mines-albi.fr</a>
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=%{<a class="moz-txt-link-freetext" href="ldap:dcMailQuota">ldap:dcMailQuota</a>}M
user_filter = (&(objectClass=posixAccount)(|(uid=%n)(<a class="moz-txt-link-abbreviated" href="mailto:mail=%n@mines-albi.fr">mail=%n@mines-albi.fr</a>)))
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;
}

</pre>
  </body>
</html>