From 3d8b0ac104dee68b47d9a4d2ef622e7f1acdd7a4 Mon Sep 17 00:00:00 2001
From: Guilhem Moulin <guilhem@fripost.org>
Date: Wed, 27 Nov 2013 01:26:36 +0100
Subject: Reorganization.

---
 common.yml                                         |  24 +-
 group_vars/all.yml                                 |   9 +
 .../common-LDAP/files/etc/ldap/schema/fripost.ldif | 190 ++++++++
 .../files/var/lib/ldap/fripost/DB_CONFIG           |   5 +
 roles/common-LDAP/handlers/main.yml                |   2 +
 roles/common-LDAP/tasks/main.yml                   |  67 +++
 .../templates/etc/ldap/database.ldif.j2            | 498 +++++++++++++++++++++
 roles/common-SQL/tasks/main.yml                    |  29 ++
 roles/common/files/etc/ldap/schema/fripost.ldif    | 190 --------
 roles/common/files/var/lib/ldap/fripost/DB_CONFIG  |   5 -
 roles/common/handlers/main.yml                     |   3 -
 roles/common/tasks/ldap.yml                        |  67 ---
 roles/common/tasks/main.yml                        |  12 -
 roles/common/tasks/sql.yml                         |  29 --
 roles/common/templates/etc/ldap/database.ldif.j2   | 498 ---------------------
 vars.yml                                           |   9 -
 16 files changed, 822 insertions(+), 815 deletions(-)
 create mode 100644 group_vars/all.yml
 create mode 100644 roles/common-LDAP/files/etc/ldap/schema/fripost.ldif
 create mode 100644 roles/common-LDAP/files/var/lib/ldap/fripost/DB_CONFIG
 create mode 100644 roles/common-LDAP/handlers/main.yml
 create mode 100644 roles/common-LDAP/tasks/main.yml
 create mode 100644 roles/common-LDAP/templates/etc/ldap/database.ldif.j2
 create mode 100644 roles/common-SQL/tasks/main.yml
 delete mode 100644 roles/common/files/etc/ldap/schema/fripost.ldif
 delete mode 100644 roles/common/files/var/lib/ldap/fripost/DB_CONFIG
 delete mode 100644 roles/common/tasks/ldap.yml
 delete mode 100644 roles/common/tasks/sql.yml
 delete mode 100644 roles/common/templates/etc/ldap/database.ldif.j2
 delete mode 100644 vars.yml

diff --git a/common.yml b/common.yml
index 2c555f9..cea8611 100644
--- a/common.yml
+++ b/common.yml
@@ -1,7 +1,27 @@
 ---
+# XXX: This organization is unfortunate. As of Ansible 1.4, roles are
+# applied playbook by playbook and not globally for the whole inventory;
+# therefore if two playbooks are given the role 'common', the tasks
+# defined in 'common' would be run twice.
+# The quickfix to ensure that plays are role-disjoint is to create a
+# separate play for each role. Of course the downside is that we loose
+# (most of) the advantage of roles...
+
 - name: Common tasks
   hosts: all
-  vars_files:
-    - vars.yml
   roles:
     - common
+
+- name: Common SQL tasks
+  hosts: MDA:webmail:backup
+  gather_facts: False
+  tags: mysql,sql
+  roles:
+    - common-SQL
+
+- name: Common LDAP tasks
+  hosts: MDA:MSA:lists:LDAP-producer:MX
+  gather_facts: False
+  tags: slapd,ldap
+  roles:
+    - common-LDAP
diff --git a/group_vars/all.yml b/group_vars/all.yml
new file mode 100644
index 0000000..2cd3a42
--- /dev/null
+++ b/group_vars/all.yml
@@ -0,0 +1,9 @@
+---
+postfix_instance:
+  # The keys are the group names associated with a Postfix role, and the
+  # values are the name and group (optional) of the instance dedicated
+  # to that role.
+  IMAP:    { name: mda                }
+  MX:      { name: mta-in, group: mta }
+  MTA-out: { name: mta-out,group: mta }
+  MSA:     { name: msa                }
diff --git a/roles/common-LDAP/files/etc/ldap/schema/fripost.ldif b/roles/common-LDAP/files/etc/ldap/schema/fripost.ldif
new file mode 100644
index 0000000..851988e
--- /dev/null
+++ b/roles/common-LDAP/files/etc/ldap/schema/fripost.ldif
@@ -0,0 +1,190 @@
+# Fripost's LDAP schema
+# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Load this file with
+#
+#   ldapadd -Y EXTERNAL -H ldapi:/// -f fripost.ldif
+#
+# It will load the schema. To perform modifications, the easiest way is to
+#
+#  * Save the database:      slapcat -b 'o=mailHosting,dc=fripost,dc=dev' > /tmp/db.ldif
+#  * Save the configuration: slapcat -n0 > /tmp/config.ldif
+#  * Backup slap.d:          cp -a /etc/ldap/slapd.d/ /tmp/slap.d_back
+#  * Edit the schema in /tmp/config.ldif
+#  * Load the new config:    mkdir -m 0700 /tmp/slapd.d_new && slapadd -F /tmp/slapd.d_new -n0 -l /tmp/config.ldif
+#  * Stop slapd:             /etc/init.d/slapd stop
+#  * Load the new config:    rm -rf /etc/ldap/slapd.d/ && mv /tmp/slapd.d_new /etc/ldap/slapd.d && chown -R openldap:openldap /etc/ldap/slapd.d
+#  * Create indexes:         sudo -u openldap slapindex -b 'o=mailHosting,dc=fripost,dc=dev'
+#  * Start slapd:            /etc/init.d/slapd start
+#    If it fails, remove the existing database and see what's wrong
+#                 rm -rf /var/lib/ldap/dev/* && sudo -u openldap slapadd -b 'o=mailHosting,dc=fripost,dc=org' -l /tmp/db.ldif
+#
+#
+# /!\ WARN: All modification to the ACL should be reflected to the test
+# /!\ suite as well!
+#
+#
+# References:
+# - http://courier.svn.sourceforge.net/svnroot/courier/trunk/courier-authlib/authldap.schema
+# - http://www.qmail-ldap.org/wiki/index.php/Qmail.schema
+# - http://www.wanderingbarque.com/howtos/mailserver/mailserver.html
+
+
+# 1.3.6.1.4.1.40011        Fripost's OID
+# 1.3.6.1.4.1.40011.1
+# 1.3.6.1.4.1.40011.1.2    fripost LDAP Elements
+# 1.3.6.1.4.1.40011.1.2.1  AttributeTypes
+# 1.3.6.1.4.1.40011.1.2.2  ObjectClasses
+# 1.3.6.1.4.1.40011.1.2.3  Syntax Definitions
+
+# This schema depends on:
+# - core.schema
+# - cosine.schema
+# - nis.schema
+
+
+dn: cn=fripost-master,cn=schema,cn=config
+objectClass: olcSchemaConfig
+#
+# Attributes: 1.3.6.1.4.1.40011.1.1
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.1 NAME 'fvd'
+    DESC 'A virtual mail domain'
+    EQUALITY caseIgnoreIA5Match
+    SUBSTR caseIgnoreIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.2 NAME 'fvl'
+    DESC 'The local part of a virtual user, alias, list or list command'
+    EQUALITY caseIgnoreIA5Match
+    SUBSTR caseIgnoreIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+#
+# This is redundant since we always use DNs of the form
+#     fvl=localpart,fvd=domainpart.tld,...
+# (But Postfix doesn't allow the use of '%u' and '%d' from the query in
+# its 'result_format'.)
+# It is a priori insecure to allow arbitrary values here since users
+# will modify this value themselves, however our Postfix will only
+# accept well-formed values, enforced by a custom filter:
+#    query_filter = (&...(fripostLocalAlias=%u#%d))
+#    result_attribute = fripostLocalAlias
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.3 NAME 'fripostLocalAlias'
+    DESC 'A local alias, typically localpart#domainpart.tld'
+    EQUALITY caseIgnoreIA5Match
+    SUBSTR caseIgnoreIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.4 NAME 'fripostMaildrop'
+    DESC 'An email address the virtual alias should be mapped to'
+    EQUALITY caseIgnoreIA5Match
+    SUBSTR caseIgnoreIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+#
+# We are creating a new attribute, optional in virtual domains and
+# users, because the presence index should *not* apply to the
+# mandatory attribute above.
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.5 NAME 'fripostOptionalMaildrop'
+    DESC 'An optional email address for catch-all aliases on domains and users'
+    EQUALITY caseIgnoreIA5Match
+    SUBSTR caseIgnoreIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.6 NAME 'fripostIsStatusActive'
+    DESC 'When present, a token locking the entry in an inactive state'
+    EQUALITY booleanMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.7 NAME 'fripostPendingToken'
+    DESC 'Is the entry pending?'
+    EQUALITY caseExactMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} SINGLE-VALUE )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.8 NAME 'fripostUserQuota'
+    DESC 'The quota on a user e.g., "50MB"'
+    EQUALITY caseExactMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32} SINGLE-VALUE )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.9 NAME 'fripostCanAddDomain'
+    DESC 'A user/domain that can add domains'
+    SUP distinguishedName )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.10 NAME 'fripostCanAddAlias'
+    DESC 'A user/domain that can add aliases under the parent domain'
+    SUP distinguishedName )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.11 NAME 'fripostCanAddList'
+    DESC 'A user/domain that can add lists under the parent domain'
+    SUP distinguishedName )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.12 NAME 'fripostOwner'
+    DESC 'A user that owns under parent domain'
+    SUP distinguishedName )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.13 NAME 'fripostPostmaster'
+    DESC 'A user that is a postmaster of the parent domain'
+    SUP distinguishedName )
+#
+olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.14 NAME 'fripostListManager'
+    DESC 'The list manager'
+    EQUALITY caseIgnoreMatch
+    SUBSTR caseIgnoreSubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} SINGLE-VALUE )
+#
+#
+# Objects: 1.3.6.1.4.1.40011.1.2
+#
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.1 NAME 'FripostVirtual'
+    AUXILIARY
+    DESC 'Virtual mail hosting'
+    MAY ( fripostCanAddDomain ) )
+#
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.2 NAME 'FripostVirtualDomain'
+    SUP top STRUCTURAL
+    DESC 'Virtual domain'
+    MUST ( fvd $ fripostIsStatusActive )
+    MAY ( fripostCanAddAlias $ fripostCanAddList $
+          fripostOwner $ fripostPostmaster $
+          fripostOptionalMaildrop $ description ) )
+#
+# | TODO: add limits here
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.3 NAME 'FripostVirtualUser'
+    SUP top STRUCTURAL
+    DESC 'Virtual user'
+    MUST ( fvl $ userPassword $ fripostIsStatusActive )
+    MAY ( fripostUserQuota $ fripostOptionalMaildrop $ description) )
+#
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.4 NAME 'FripostVirtualAlias'
+    SUP top STRUCTURAL
+    DESC 'Virtual alias'
+    MUST ( fvl $ fripostMaildrop $ fripostIsStatusActive )
+    MAY ( fripostOwner $ description ) )
+#
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.5 NAME 'FripostVirtualList'
+    SUP top STRUCTURAL
+    DESC 'Virtual list'
+    MUST ( fvl $ fripostListManager $ fripostIsStatusActive $ fripostLocalAlias )
+    MAY ( fripostOwner $ description ) )
+#
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.6 NAME 'FripostVirtualListCommand'
+    SUP top STRUCTURAL
+    DESC 'Virtual list command'
+    MUST ( fvl $ fripostLocalAlias ) )
+#
+olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.7 NAME 'FripostPendingEntry'
+    SUP top AUXILIARY
+    DESC 'Virtual pending entry'
+    MAY ( fripostPendingToken ) )
diff --git a/roles/common-LDAP/files/var/lib/ldap/fripost/DB_CONFIG b/roles/common-LDAP/files/var/lib/ldap/fripost/DB_CONFIG
new file mode 100644
index 0000000..0bd4e58
--- /dev/null
+++ b/roles/common-LDAP/files/var/lib/ldap/fripost/DB_CONFIG
@@ -0,0 +1,5 @@
+set_cachesize 0 5242880 1
+# 5MB cachesize, allow defragmentation
+set_lk_max_objects 1500
+set_lk_max_locks 1500
+set_lk_max_lockers 1500
diff --git a/roles/common-LDAP/handlers/main.yml b/roles/common-LDAP/handlers/main.yml
new file mode 100644
index 0000000..6972af2
--- /dev/null
+++ b/roles/common-LDAP/handlers/main.yml
@@ -0,0 +1,2 @@
+- name: Restart slapd
+  service: name=slapd state=restarted
diff --git a/roles/common-LDAP/tasks/main.yml b/roles/common-LDAP/tasks/main.yml
new file mode 100644
index 0000000..cb1e835
--- /dev/null
+++ b/roles/common-LDAP/tasks/main.yml
@@ -0,0 +1,67 @@
+- name: Install OpenLDAP
+  apt: pkg={{ item }}
+  with_items:
+    - slapd
+    - ldap-utils
+    - ldapvi
+    - db-util
+    - python-ldap
+
+# Upon install slapd create and populate a database under /var/lib/ldap.
+# We clear it up and create a children directory to get finer-grain
+# control.
+- name: Clear empty /var/lib/ldap
+  # Don't remove the database (and fail) if it contains something else
+  # than its suffix or cn=admin,...
+  openldap: dbdirectory=/var/lib/ldap ignoredn=cn=admin
+            state=absent
+
+- name: Create directory /var/lib/ldap/fripost
+  file: path=/var/lib/ldap/fripost
+        owner=openldap group=openldap
+        state=directory
+        mode=0700
+
+- name: Copy /var/lib/ldap/fripost/DB_CONFIG
+  copy: src=var/lib/ldap/fripost/DB_CONFIG
+        dest=/var/lib/ldap/fripost/DB_CONFIG
+        owner=openldap group=openldap
+        mode=0600
+  notify:
+    # Not sure if required
+    - Restart slapd
+
+- name: Create directory /etc/ldap/fripost
+  file: path=/etc/ldap/fripost
+        owner=root group=root
+        state=directory
+        mode=0755
+
+- name: Copy fripost database definition
+  template: src=etc/ldap/database.ldif.j2
+            dest=/etc/ldap/fripost/database.ldif
+            owner=root group=root
+            mode=0600
+
+- name: Copy fripost schema
+  copy: src=etc/ldap/schema/fripost.ldif
+        dest=/etc/ldap/schema/fripost.ldif
+        owner=root group=root
+        mode=0644
+
+- name: Load fripost's schema and configure the database
+  openldap: target=/etc/ldap/{{ item }} state=present
+  with_items:
+    - schema/fripost.ldif
+    # TODO load other required schemas *before* loading the database
+    - fripost/database.ldif
+
+- name: Load LDAP modules
+  openldap: module={{ item }}.la state=present
+  with_items:
+    # TODO only if provider
+    - syncprov
+    # TODO only if writable
+    - constraint
+
+# TODO: authz constraint syncprov syncrepl
diff --git a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
new file mode 100644
index 0000000..19fcdd0
--- /dev/null
+++ b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
@@ -0,0 +1,498 @@
+# Fripost's LDAP database definition
+# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+dn: olcDatabase=hdb,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcHdbConfig
+olcDbDirectory: /var/lib/ldap/fripost
+olcSuffix: o=mailHosting,dc=fripost,dc=org
+olcLastMod: TRUE
+olcDbCheckpoint: 512 15
+# Require LDAPv3 protocol and authentication prior to directory
+# operations.
+olcRequires: LDAPv3 authc
+# We don't want to give "canAdd{Alias,List}" write access to alias/list
+# attributes.
+olcAddContentAcl: FALSE
+# The root user has all rights on the whole database (when SASL-binding
+# on a UNIX socket).
+olcRootDN: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
+#
+#
+########################################################################
+########################################################################
+# Performance considerations
+#
+# To reindex an existing database, you have to
+#  * Stop slapd     sudo service slapd stop
+#  * Reindex        su openldap -c "slapindex -b 'o=mailHosting,dc=fripost,dc=org'"
+#  * Restart slapd  sudo service slapd start
+#
+# References
+# - https://wiki.zimbra.com/wiki/OpenLDAP_Performance_Tuning_5.0
+# - http://www.openldap.org/doc/admin24/tuning.html
+# - http://www.openldap.org/faq/data/cache/42.html
+# - http://www.openldap.org/faq/data/cache/136.html
+# - http://www.zytrax.com/books/ldap/apa/indeces.html
+#
+olcDbIndex: objectClass eq
+# Let us make Postfix's life easier. TODO: only if MX, lists.f.o, MDA, etc.
+olcDbIndex: fripostIsStatusActive,fvd,fvl,fripostLocalAlias eq
+olcDbIndex: fripostOptionalMaildrop pres
+# SyncProv/SyncRepl specific indexing. TODO: only if SyncProv/SyncRepl
+olcDbIndex: entryCSN,entryUUID eq
+#
+#
+#
+# 1. On single- and dual-core systems, change the maximum number of
+# threads to 8. (The default, 16, is fine for 4- and 8-core systems.)
+#
+#       dn: cn=config
+#       changetype: modify
+#       add: olcThreads
+#       olcThreads: 8
+#
+#
+# 2. It may be a good idea to modify DB_CONFIG, depending on the output
+# of
+#
+#   db_stat -mh /var/lib/ldap/fripost | head -16
+#
+# (For optimal performance, the Requested pages found in the cache
+# should be above 95%, and the dirty/clean pages forced from the cache
+# should be 0.)
+#
+# and
+#
+#   db_stat -ch /var/lib/ldap/fripost | head -16
+#
+# (For optimal performance, usage should be within 85% of the configured
+# values.)
+#
+#
+########################################################################
+########################################################################
+# Access control
+# /!\ WARN: All modification to the ACL should be reflected to the test
+# /!\ suite as well!
+#
+# References:
+# - http://www.openldap.org/doc/admin24/access-control.html
+# - http://www.openldap.org/faq/data/cache/189.html
+# - http://www.openldap.org/faq/data/cache/1140.html
+# - http://www.openldap.org/faq/data/cache/1133.html
+# - man 5 slapd.access
+#
+#
+########################################################################
+# Most common services: Postfix, Amavis, SASLauth, Dovecot
+# (Most used ACLs are cheaper when written first.)
+#
+# Postfix have read access to the attribute they need.
+olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        attrs=entry,objectClass,fvd,fvl,fripostMaildrop,fripostOptionalMaildrop,fripostLocalAlias
+        filter=(&(|(objectClass=FripostVirtualDomain)(objectClass=FripostVirtualUser)(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand))(!(objectClass=FripostPendingEntry))(!(fripostIsStatusActive=FALSE)))
+    by dn.exact="cn=Postfix,ou=services,o=mailHosting,dc=fripost,dc=org" =rsd
+    by users =0 break
+# Search lists and domain owners
+olcAccess: to dn.exact="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        attrs=entry
+    by dn.exact="cn=Postfix,ou=services,o=mailHosting,dc=fripost,dc=org" =s
+    by dn.exact="gidNumber=8+uidNumber=8,cn=peercred,cn=external,cn=auth" =s
+    by users =0 break
+#
+# Search domain owners / postmasters
+olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        attrs=entry,objectClass,fvd,fvl,fripostPostmaster,fripostOwner
+        filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry))(!(fripostIsStatusActive=FALSE)))
+    by dn.exact="gidNumber=8+uidNumber=8,cn=peercred,cn=external,cn=auth" =rsd
+    by users =0 break
+#
+# Anonymous can authenticate into the services. (But not read or write the password.)
+olcAccess: to dn.one="ou=services,o=mailHosting,dc=fripost,dc=org"
+        attrs=userPassword
+    by realanonymous =xd
+#
+# That's necessary for SASL proxy Authorize the web application.
+olcAccess: to dn.exact="cn=AdminWebPanel,ou=services,o=mailHosting,dc=fripost,dc=org"
+        attrs=entry,objectClass,authzTo
+    by realanonymous =x
+#
+# 1. The WebPanel itself cannot bind, read or write passwords. This
+# guarantees that, if an attacker gains its priviledge, it will *not* be
+# able to change user passwords (which would allow him/her to read every
+# emails). This is a trick to tackle the absence of 'realgroup'.
+# 2. Anonymous users can bind.
+# 3. Users can change their password (but not read it).
+# 4. The postmaster of a domain can change (replace) his/her users' password (but not read it).
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualUser)
+        attrs=userPassword
+    by realdn.exact="uid=AdminWebPanel@fripost.org,cn=auth" =0
+    by realanonymous =xd
+    by realself =w
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =w
+    by dn.onelevel="ou=managers,o=mailHosting,dc=fripost,dc=org" =w
+#
+# A catch-all, to be sure that noone else have access to the passwords.
+olcAccess: to dn.subtree="o=mailHosting,dc=fripost,dc=org"
+        attrs=userPassword
+    by * =0
+#
+#
+########################################################################
+# Virtual subtree, pending token and general access
+#
+# 1. Users need further access. We use a set to deny all access to non-users without
+# having a need for an expensive LDAP search (URL) in the AuthzTo.
+# /!\ The objectClass "FripostVirtualUser" is case-sensitive in this case!
+# 2,3. Services that need particular access on the tree.
+# 4. Managers have read/write access to the "virtual" subtree.
+olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+    by set.exact="user/objectClass & [FripostVirtualUser]" =0 break
+    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" =0 break
+    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =0 break
+    by dn.onelevel="ou=managers,o=mailHosting,dc=fripost,dc=org" =wrscd
+#
+# Only the domain Postmasters and Owners can delete the 'pending' status on domains.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(&(objectClass=FripostVirtualDomain)(objectClass=FripostPendingEntry))
+        attrs=objectClass val=FripostPendingEntry
+    by dnattr=fripostPostmaster =z break
+    by dnattr=fripostOwner =z break
+    by * =0 break
+#
+# The list creation service can delete the 'pending' status on lists and list commands.
+olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(&(|(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand))(objectClass=FripostPendingEntry))
+        attrs=objectClass val=FripostPendingEntry
+    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" =z break
+    by * +0 break
+#
+# ObjectClass is a public attribute: everyone can read and search it.
+olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        attrs=objectClass
+    by * +rscd
+#
+# The pending token is not public, but domain owner and postmasters can check their and
+# delete it (if the token matches, but the check is done on the library side).
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(&(objectClass=FripostVirtualDomain)(objectClass=FripostPendingEntry))
+        attrs=fripostPendingToken
+    by dnattr=fripostPostmaster =zcd break
+    by dnattr=fripostOwner =zcd break
+    by * +0 break
+#
+# The list creation service can delete the 'pending' status on lists and list commands.
+olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(&(|(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand))(objectClass=FripostPendingEntry))
+        attrs=fripostPendingToken
+    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" +z
+    by * +0
+#
+# The cleaning service can list the (expired) pending entries and delete them.
+olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(objectClass=FripostPendingEntry)
+        attrs=entry
+    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =zrd break
+    by * =0 break
+#
+# One can search search everywhere in the virtual tree.
+olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        attrs=entry
+    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" +s
+    by * =s break
+#
+# We're giving away create/delete access on the children attributes, but we will be carefull
+# with the 'entry' permissions.
+olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(objectClass=FripostVirtual)
+        attrs=children
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" =w
+    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =z
+olcAccess: to dn.one="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=children
+    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =z
+    by * break
+olcAccess: to dn.one="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry)))
+        attrs=children
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" =w
+#
+# The cleaning service needs to know when entries have been created.
+olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(objectClass=FripostPendingEntry)
+        attrs=createTimestamp
+    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =s
+#
+# Users can use these in filters (e.g., to list the entries they have created).
+olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(|(objectClass=FripostVirtualDomain)(objectClass=FripostVirtualUser)(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList))
+        attrs=fripostOwner,fripostPostmaster,fripostCanAddAlias,fripostCanAddList
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" =s break
+#
+#
+########################################################################
+# Virtual subtree, domains
+#
+# 1. The postmaster of a domain can give (or take back) people the right to create
+# aliases.
+# 2,3. People that can create aliases can list the members of the group.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=fripostCanAddAlias
+    by dnattr=fripostPostmaster =wrscd
+    by dnattr=fripostOwner =rscd
+    by set.exact="this/fripostCanAddAlias & (user | user/-1)" =rscd
+#
+# 1. The postmaster of a domain can give (or take back) people the right to create lists.
+# 2,3. People that can create lists can list the members of the group.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=fripostCanAddList
+    by dnattr=fripostPostmaster =wrscd
+    by dnattr=fripostOwner =rscd
+    by set.exact="this/fripostCanAddList & (user | user/-1)" =rscd
+#
+# 1-3. Noone (but the managers) can appoint domain Owners or Postmasters.
+# But people that can create aliases and lists can list the members of their group.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=fripostOwner,fripostPostmaster
+    by dnattr=fripostOwner =rscd
+    by dnattr=fripostPostmaster =rscd
+    by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" =rscd
+    by dn.onelevel,expand="$0" +d
+    by * +0
+#
+# 1. Domain owners can edit their entry's attributes.
+# 2. So can domain postmasters.
+# 3. Domain users can read the public domain attributes.
+# 4. So can users with "canAddAlias" or "canAddList" access.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=fvd,fripostIsStatusActive,description
+    by dnattr=fripostOwner =wrscd
+    by dnattr=fripostPostmaster =wrscd
+    by dn.onelevel,expand="$0" =rscd
+    by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" =rscd
+#
+# 1. Domain owners can edit their entry's attributes.
+# 2. So can domain postmasters.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=@fripostVirtualDomain
+    by dnattr=fripostOwner =wrscd
+    by dnattr=fripostPostmaster =wrscd
+    by * +0
+#
+# Users with "addDomain" access can create new entries, but only if
+# there is a pending token.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(&(objectClass=FripostVirtualDomain)(objectClass=FripostPendingEntry)(fripostPendingToken=*))
+        attrs=entry
+    by set.exact="this/-1/fripostCanAddDomain & (user | user/-1)" +a break
+    by * +0 break
+#
+# 1. Domain owners can delete their domain (and read the entry).
+# 2. So can domain postmasters.
+# 3. Domain users can read the domain entry (but not delete it).
+# 4. So can users with "canAddAlias" or "canAddList" rights.
+olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+        filter=(objectClass=FripostVirtualDomain)
+        attrs=entry
+    by dnattr=fripostOwner +zrd
+    by dnattr=fripostPostmaster +zrd
+    by dn.onelevel,expand="$0" +rd
+    by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" +rd
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +0
+#
+# Reserved local parts are reserved. /!\ The case must be insensitive
+# - postmaster: RFC 822, appendix C.6
+# - abuse:      RFC 2142, section 4
+olcAccess: to dn.regex="^fvl=(postmaster|abuse),fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
+    by * =0
+#
+#
+########################################################################
+# Virtual subtree, users
+#
+# Users and their postmaster can read the quota (but not change it).
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualUser)
+        attrs=fripostUserQuota
+    by self =rscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =rscd
+#
+# 1. Users can modify their own entry.
+# 2. So can their postmasters.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualUser)
+        attrs=@FripostVirtualUser
+    by self =wrscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
+#
+# 1. Users can read their entry (but not delete it).
+# 2. Postmasters can create users (but not delete them).
+# (Provided that they have +a access to the parent's "children" attribute.)
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualUser)
+        attrs=entry
+    by self +rd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +ard
+#
+#
+########################################################################
+# Virtual subtree, aliases
+#
+# 1. The alias owner can list the ownership of the entry.
+# 2. The domain owner can add/delete/change the ownership of the entry.
+# 3. So can the domain postmasters.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualAlias)
+        attrs=fripostOwner
+    by dnattr=fripostOwner =rscd continue
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
+    by * +0
+#
+# 1. The alias owners can edit the rest of their entry's attributes.
+# 2. So can the domain owners.
+# 3. So can the domain postmasters.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualAlias)
+        attrs=@FripostVirtualAlias
+    by dnattr=fripostOwner =wrscd
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
+#
+# 1. The alias owners can read and delete the entry.
+# 2. So can the domain owner.
+# 3. So can the domain postmaster.
+# 4. Users with "canAddAlias" access (either explicitely, or as a wildcard) for the domain can create aliases for that domain.
+# (But *not* delete them, unless also owner.)
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualAlias)
+        attrs=entry
+    by dnattr=fripostOwner +zrd continue
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" +wrd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +wrd
+    by set.exact="this/-1/fripostCanAddAlias & (user | user/-1)" +a
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +0
+#
+#
+########################################################################
+# Virtual subtree, lists
+#
+# 1. The list owner can list the ownership of the entry.
+# 2. The domain owner can add/delete/change the ownership of the entry.
+# 3. So can the domain postmasters.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualList)
+        attrs=fripostOwner
+    by dnattr=fripostOwner =rscd continue
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
+    by * +0
+#
+# 1. The list owner read (but not edit) the transport-related attributes.
+# 2. So can the domain ower.
+# 3. So can the domain postmaster.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualList)
+        attrs=fripostListManager
+    by dnattr=fripostOwner =rscd
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" =rscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =rscd
+#
+# Local aliases are for internal use only.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualList)
+        attrs=fripostLocalAlias
+    by * =0
+#
+# 1. The list owners can edit their entry's attributes.
+# 2. So can the domain owners.
+# 3. So can the domain postmasters.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualList)
+        attrs=@FripostVirtualList
+    by dnattr=fripostOwner =wrscd
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
+#
+# 1. The domain owner can create and delete lists, but only those with a 'pending' status
+# 2. So can the domain postmaster.
+# 3. The list owner can delete pending lists.
+# 4. The entry creator can delete pending lists (needed to be able to rollback).
+# 5. People with "canAddList" access can create lists, but only with a 'pending' status.
+# 6. The list creation service can search and browse the entry.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(&(objectClass=FripostVirtualList)(objectClass=FripostPendingEntry))
+        attrs=entry
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" +w break
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +w break
+    by dnattr=fripostOwner +z continue
+    by dnattr=creatorsName +z continue
+    by set.exact="this/-1/fripostCanAddList & (user | user/-1)" +a break
+    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" +rd
+    by * +0 break
+#
+# 1. The domain owner can create and delete list commands, but only those with a 'pending' status
+# 2. So can the domain postmaster.
+# 3. The entry creator can delete pending list commands (needed to be able to rollback).
+# 4. People with "canAddList" access can create list commands, but only with a 'pending' status.
+# 5. The list creation service can search and browse the entry.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(&(objectClass=FripostVirtualListCommand)(objectClass=FripostPendingEntry))
+        attrs=entry
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" +w
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +w
+    by dnattr=creatorsName +z continue
+    by set.exact="this/-1/fripostCanAddList & (user | user/-1)" +a
+    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" +rd
+    by * +0
+#
+# 1. The list owners can read the entry.
+# 2. So can the domain's Owner.
+# 3. So can the domain's Postmaster.
+olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
+        filter=(objectClass=FripostVirtualList)
+        attrs=entry
+    by dnattr=fripostOwner +rd
+    by group/FripostVirtualDomain/fripostOwner.expand="$1" +rd
+    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +rd
+    by * +0
+#
+#
+########################################################################
+# Catchall
+#
+# Users with "canAddDomain" access can see that they have the right
+# to create domains.
+olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(objectClass=FripostVirtual)
+        attrs=entry
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +rd
+olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+        filter=(objectClass=FripostVirtual)
+        attrs=fripostCanAddDomain
+    by set.exact="this/fripostCanAddDomain & (user | user/-1)" =rscd
+# Catch the break above
+olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
+    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +0
+# vim: set filetype=ldif :
diff --git a/roles/common-SQL/tasks/main.yml b/roles/common-SQL/tasks/main.yml
new file mode 100644
index 0000000..e32c863
--- /dev/null
+++ b/roles/common-SQL/tasks/main.yml
@@ -0,0 +1,29 @@
+- name: Install MySQL
+  apt: pkg={{ item }}
+  with_items:
+    # XXX: In non-interactive mode apt-get doesn't put a password on
+    # MySQL's root user; we fix that on the next task, but an intruder
+    # could exploit the race condition and for instance create dummy
+    # users.
+    - mysql-common
+    - mysql-server
+    - python-mysqldb
+
+- name: Force root to use UNIX permissions
+  mysql_user: name=root auth_plugin=auth_socket
+              state=present
+
+- name: Disallow anonymous and TCP/IP root login
+  mysql_user: name={{ item.name|default('') }} host={{ item.host }}
+              state=absent
+  with_items:
+    - {             host: '{{ inventory_hostname_short }}' }
+    - {             host: 'localhost' }
+    - {             host: '127.0.0.1'}
+    - {             host: '::1'}
+    - { name: root, host: '{{ inventory_hostname_short }}' }
+    - { name: root, host: '127.0.0.1'}
+    - { name: root, host: '::1'}
+
+- name: Start MySQL
+  service: name=mysql state=started
diff --git a/roles/common/files/etc/ldap/schema/fripost.ldif b/roles/common/files/etc/ldap/schema/fripost.ldif
deleted file mode 100644
index 851988e..0000000
--- a/roles/common/files/etc/ldap/schema/fripost.ldif
+++ /dev/null
@@ -1,190 +0,0 @@
-# Fripost's LDAP schema
-# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# Load this file with
-#
-#   ldapadd -Y EXTERNAL -H ldapi:/// -f fripost.ldif
-#
-# It will load the schema. To perform modifications, the easiest way is to
-#
-#  * Save the database:      slapcat -b 'o=mailHosting,dc=fripost,dc=dev' > /tmp/db.ldif
-#  * Save the configuration: slapcat -n0 > /tmp/config.ldif
-#  * Backup slap.d:          cp -a /etc/ldap/slapd.d/ /tmp/slap.d_back
-#  * Edit the schema in /tmp/config.ldif
-#  * Load the new config:    mkdir -m 0700 /tmp/slapd.d_new && slapadd -F /tmp/slapd.d_new -n0 -l /tmp/config.ldif
-#  * Stop slapd:             /etc/init.d/slapd stop
-#  * Load the new config:    rm -rf /etc/ldap/slapd.d/ && mv /tmp/slapd.d_new /etc/ldap/slapd.d && chown -R openldap:openldap /etc/ldap/slapd.d
-#  * Create indexes:         sudo -u openldap slapindex -b 'o=mailHosting,dc=fripost,dc=dev'
-#  * Start slapd:            /etc/init.d/slapd start
-#    If it fails, remove the existing database and see what's wrong
-#                 rm -rf /var/lib/ldap/dev/* && sudo -u openldap slapadd -b 'o=mailHosting,dc=fripost,dc=org' -l /tmp/db.ldif
-#
-#
-# /!\ WARN: All modification to the ACL should be reflected to the test
-# /!\ suite as well!
-#
-#
-# References:
-# - http://courier.svn.sourceforge.net/svnroot/courier/trunk/courier-authlib/authldap.schema
-# - http://www.qmail-ldap.org/wiki/index.php/Qmail.schema
-# - http://www.wanderingbarque.com/howtos/mailserver/mailserver.html
-
-
-# 1.3.6.1.4.1.40011        Fripost's OID
-# 1.3.6.1.4.1.40011.1
-# 1.3.6.1.4.1.40011.1.2    fripost LDAP Elements
-# 1.3.6.1.4.1.40011.1.2.1  AttributeTypes
-# 1.3.6.1.4.1.40011.1.2.2  ObjectClasses
-# 1.3.6.1.4.1.40011.1.2.3  Syntax Definitions
-
-# This schema depends on:
-# - core.schema
-# - cosine.schema
-# - nis.schema
-
-
-dn: cn=fripost-master,cn=schema,cn=config
-objectClass: olcSchemaConfig
-#
-# Attributes: 1.3.6.1.4.1.40011.1.1
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.1 NAME 'fvd'
-    DESC 'A virtual mail domain'
-    EQUALITY caseIgnoreIA5Match
-    SUBSTR caseIgnoreIA5SubstringsMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.2 NAME 'fvl'
-    DESC 'The local part of a virtual user, alias, list or list command'
-    EQUALITY caseIgnoreIA5Match
-    SUBSTR caseIgnoreIA5SubstringsMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
-#
-# This is redundant since we always use DNs of the form
-#     fvl=localpart,fvd=domainpart.tld,...
-# (But Postfix doesn't allow the use of '%u' and '%d' from the query in
-# its 'result_format'.)
-# It is a priori insecure to allow arbitrary values here since users
-# will modify this value themselves, however our Postfix will only
-# accept well-formed values, enforced by a custom filter:
-#    query_filter = (&...(fripostLocalAlias=%u#%d))
-#    result_attribute = fripostLocalAlias
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.3 NAME 'fripostLocalAlias'
-    DESC 'A local alias, typically localpart#domainpart.tld'
-    EQUALITY caseIgnoreIA5Match
-    SUBSTR caseIgnoreIA5SubstringsMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.4 NAME 'fripostMaildrop'
-    DESC 'An email address the virtual alias should be mapped to'
-    EQUALITY caseIgnoreIA5Match
-    SUBSTR caseIgnoreIA5SubstringsMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
-#
-# We are creating a new attribute, optional in virtual domains and
-# users, because the presence index should *not* apply to the
-# mandatory attribute above.
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.5 NAME 'fripostOptionalMaildrop'
-    DESC 'An optional email address for catch-all aliases on domains and users'
-    EQUALITY caseIgnoreIA5Match
-    SUBSTR caseIgnoreIA5SubstringsMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.6 NAME 'fripostIsStatusActive'
-    DESC 'When present, a token locking the entry in an inactive state'
-    EQUALITY booleanMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.7 NAME 'fripostPendingToken'
-    DESC 'Is the entry pending?'
-    EQUALITY caseExactMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} SINGLE-VALUE )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.8 NAME 'fripostUserQuota'
-    DESC 'The quota on a user e.g., "50MB"'
-    EQUALITY caseExactMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32} SINGLE-VALUE )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.9 NAME 'fripostCanAddDomain'
-    DESC 'A user/domain that can add domains'
-    SUP distinguishedName )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.10 NAME 'fripostCanAddAlias'
-    DESC 'A user/domain that can add aliases under the parent domain'
-    SUP distinguishedName )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.11 NAME 'fripostCanAddList'
-    DESC 'A user/domain that can add lists under the parent domain'
-    SUP distinguishedName )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.12 NAME 'fripostOwner'
-    DESC 'A user that owns under parent domain'
-    SUP distinguishedName )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.13 NAME 'fripostPostmaster'
-    DESC 'A user that is a postmaster of the parent domain'
-    SUP distinguishedName )
-#
-olcAttributeTypes: ( 1.3.6.1.4.1.40011.1.2.1.14 NAME 'fripostListManager'
-    DESC 'The list manager'
-    EQUALITY caseIgnoreMatch
-    SUBSTR caseIgnoreSubstringsMatch
-    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} SINGLE-VALUE )
-#
-#
-# Objects: 1.3.6.1.4.1.40011.1.2
-#
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.1 NAME 'FripostVirtual'
-    AUXILIARY
-    DESC 'Virtual mail hosting'
-    MAY ( fripostCanAddDomain ) )
-#
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.2 NAME 'FripostVirtualDomain'
-    SUP top STRUCTURAL
-    DESC 'Virtual domain'
-    MUST ( fvd $ fripostIsStatusActive )
-    MAY ( fripostCanAddAlias $ fripostCanAddList $
-          fripostOwner $ fripostPostmaster $
-          fripostOptionalMaildrop $ description ) )
-#
-# | TODO: add limits here
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.3 NAME 'FripostVirtualUser'
-    SUP top STRUCTURAL
-    DESC 'Virtual user'
-    MUST ( fvl $ userPassword $ fripostIsStatusActive )
-    MAY ( fripostUserQuota $ fripostOptionalMaildrop $ description) )
-#
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.4 NAME 'FripostVirtualAlias'
-    SUP top STRUCTURAL
-    DESC 'Virtual alias'
-    MUST ( fvl $ fripostMaildrop $ fripostIsStatusActive )
-    MAY ( fripostOwner $ description ) )
-#
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.5 NAME 'FripostVirtualList'
-    SUP top STRUCTURAL
-    DESC 'Virtual list'
-    MUST ( fvl $ fripostListManager $ fripostIsStatusActive $ fripostLocalAlias )
-    MAY ( fripostOwner $ description ) )
-#
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.6 NAME 'FripostVirtualListCommand'
-    SUP top STRUCTURAL
-    DESC 'Virtual list command'
-    MUST ( fvl $ fripostLocalAlias ) )
-#
-olcObjectClasses: ( 1.3.6.1.4.1.40011.1.2.7 NAME 'FripostPendingEntry'
-    SUP top AUXILIARY
-    DESC 'Virtual pending entry'
-    MAY ( fripostPendingToken ) )
diff --git a/roles/common/files/var/lib/ldap/fripost/DB_CONFIG b/roles/common/files/var/lib/ldap/fripost/DB_CONFIG
deleted file mode 100644
index 0bd4e58..0000000
--- a/roles/common/files/var/lib/ldap/fripost/DB_CONFIG
+++ /dev/null
@@ -1,5 +0,0 @@
-set_cachesize 0 5242880 1
-# 5MB cachesize, allow defragmentation
-set_lk_max_objects 1500
-set_lk_max_locks 1500
-set_lk_max_lockers 1500
diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml
index 51b19f7..54643ed 100644
--- a/roles/common/handlers/main.yml
+++ b/roles/common/handlers/main.yml
@@ -35,6 +35,3 @@
 
 - name: Reload Postfix
   service: name=postfix state=reloaded
-
-- name: Restart slapd
-  service: name=slapd state=restarted
diff --git a/roles/common/tasks/ldap.yml b/roles/common/tasks/ldap.yml
deleted file mode 100644
index cb1e835..0000000
--- a/roles/common/tasks/ldap.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-- name: Install OpenLDAP
-  apt: pkg={{ item }}
-  with_items:
-    - slapd
-    - ldap-utils
-    - ldapvi
-    - db-util
-    - python-ldap
-
-# Upon install slapd create and populate a database under /var/lib/ldap.
-# We clear it up and create a children directory to get finer-grain
-# control.
-- name: Clear empty /var/lib/ldap
-  # Don't remove the database (and fail) if it contains something else
-  # than its suffix or cn=admin,...
-  openldap: dbdirectory=/var/lib/ldap ignoredn=cn=admin
-            state=absent
-
-- name: Create directory /var/lib/ldap/fripost
-  file: path=/var/lib/ldap/fripost
-        owner=openldap group=openldap
-        state=directory
-        mode=0700
-
-- name: Copy /var/lib/ldap/fripost/DB_CONFIG
-  copy: src=var/lib/ldap/fripost/DB_CONFIG
-        dest=/var/lib/ldap/fripost/DB_CONFIG
-        owner=openldap group=openldap
-        mode=0600
-  notify:
-    # Not sure if required
-    - Restart slapd
-
-- name: Create directory /etc/ldap/fripost
-  file: path=/etc/ldap/fripost
-        owner=root group=root
-        state=directory
-        mode=0755
-
-- name: Copy fripost database definition
-  template: src=etc/ldap/database.ldif.j2
-            dest=/etc/ldap/fripost/database.ldif
-            owner=root group=root
-            mode=0600
-
-- name: Copy fripost schema
-  copy: src=etc/ldap/schema/fripost.ldif
-        dest=/etc/ldap/schema/fripost.ldif
-        owner=root group=root
-        mode=0644
-
-- name: Load fripost's schema and configure the database
-  openldap: target=/etc/ldap/{{ item }} state=present
-  with_items:
-    - schema/fripost.ldif
-    # TODO load other required schemas *before* loading the database
-    - fripost/database.ldif
-
-- name: Load LDAP modules
-  openldap: module={{ item }}.la state=present
-  with_items:
-    # TODO only if provider
-    - syncprov
-    # TODO only if writable
-    - constraint
-
-# TODO: authz constraint syncprov syncrepl
diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml
index ed84cb5..355b2df 100644
--- a/roles/common/tasks/main.yml
+++ b/roles/common/tasks/main.yml
@@ -9,15 +9,3 @@
 - include: ipsec.yml    tags=strongswan,ipsec
 - include: logging.yml  tags=logging
 - include: mail.yml     tags=mail,postfix
-- include: sql.yml      tags=mysql,sql
-  # XXX: the conditional here is a bit dirty, because it clutters the
-  # output with 'skipping' notices.
-  when: "'MDA'     in group_names or
-         'webmail' in group_names or
-         'backup'  in group_names"
-- include: ldap.yml     tags=slapd,ldap
-  when: "'MDA'           in group_names or
-         'MSA'           in group_names or
-         'lists'         in group_names or
-         'LDAP-producer' in group_names or
-         'MX'            in group_names"
diff --git a/roles/common/tasks/sql.yml b/roles/common/tasks/sql.yml
deleted file mode 100644
index e32c863..0000000
--- a/roles/common/tasks/sql.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-- name: Install MySQL
-  apt: pkg={{ item }}
-  with_items:
-    # XXX: In non-interactive mode apt-get doesn't put a password on
-    # MySQL's root user; we fix that on the next task, but an intruder
-    # could exploit the race condition and for instance create dummy
-    # users.
-    - mysql-common
-    - mysql-server
-    - python-mysqldb
-
-- name: Force root to use UNIX permissions
-  mysql_user: name=root auth_plugin=auth_socket
-              state=present
-
-- name: Disallow anonymous and TCP/IP root login
-  mysql_user: name={{ item.name|default('') }} host={{ item.host }}
-              state=absent
-  with_items:
-    - {             host: '{{ inventory_hostname_short }}' }
-    - {             host: 'localhost' }
-    - {             host: '127.0.0.1'}
-    - {             host: '::1'}
-    - { name: root, host: '{{ inventory_hostname_short }}' }
-    - { name: root, host: '127.0.0.1'}
-    - { name: root, host: '::1'}
-
-- name: Start MySQL
-  service: name=mysql state=started
diff --git a/roles/common/templates/etc/ldap/database.ldif.j2 b/roles/common/templates/etc/ldap/database.ldif.j2
deleted file mode 100644
index 19fcdd0..0000000
--- a/roles/common/templates/etc/ldap/database.ldif.j2
+++ /dev/null
@@ -1,498 +0,0 @@
-# Fripost's LDAP database definition
-# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-dn: olcDatabase=hdb,cn=config
-objectClass: olcDatabaseConfig
-objectClass: olcHdbConfig
-olcDbDirectory: /var/lib/ldap/fripost
-olcSuffix: o=mailHosting,dc=fripost,dc=org
-olcLastMod: TRUE
-olcDbCheckpoint: 512 15
-# Require LDAPv3 protocol and authentication prior to directory
-# operations.
-olcRequires: LDAPv3 authc
-# We don't want to give "canAdd{Alias,List}" write access to alias/list
-# attributes.
-olcAddContentAcl: FALSE
-# The root user has all rights on the whole database (when SASL-binding
-# on a UNIX socket).
-olcRootDN: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
-#
-#
-########################################################################
-########################################################################
-# Performance considerations
-#
-# To reindex an existing database, you have to
-#  * Stop slapd     sudo service slapd stop
-#  * Reindex        su openldap -c "slapindex -b 'o=mailHosting,dc=fripost,dc=org'"
-#  * Restart slapd  sudo service slapd start
-#
-# References
-# - https://wiki.zimbra.com/wiki/OpenLDAP_Performance_Tuning_5.0
-# - http://www.openldap.org/doc/admin24/tuning.html
-# - http://www.openldap.org/faq/data/cache/42.html
-# - http://www.openldap.org/faq/data/cache/136.html
-# - http://www.zytrax.com/books/ldap/apa/indeces.html
-#
-olcDbIndex: objectClass eq
-# Let us make Postfix's life easier. TODO: only if MX, lists.f.o, MDA, etc.
-olcDbIndex: fripostIsStatusActive,fvd,fvl,fripostLocalAlias eq
-olcDbIndex: fripostOptionalMaildrop pres
-# SyncProv/SyncRepl specific indexing. TODO: only if SyncProv/SyncRepl
-olcDbIndex: entryCSN,entryUUID eq
-#
-#
-#
-# 1. On single- and dual-core systems, change the maximum number of
-# threads to 8. (The default, 16, is fine for 4- and 8-core systems.)
-#
-#       dn: cn=config
-#       changetype: modify
-#       add: olcThreads
-#       olcThreads: 8
-#
-#
-# 2. It may be a good idea to modify DB_CONFIG, depending on the output
-# of
-#
-#   db_stat -mh /var/lib/ldap/fripost | head -16
-#
-# (For optimal performance, the Requested pages found in the cache
-# should be above 95%, and the dirty/clean pages forced from the cache
-# should be 0.)
-#
-# and
-#
-#   db_stat -ch /var/lib/ldap/fripost | head -16
-#
-# (For optimal performance, usage should be within 85% of the configured
-# values.)
-#
-#
-########################################################################
-########################################################################
-# Access control
-# /!\ WARN: All modification to the ACL should be reflected to the test
-# /!\ suite as well!
-#
-# References:
-# - http://www.openldap.org/doc/admin24/access-control.html
-# - http://www.openldap.org/faq/data/cache/189.html
-# - http://www.openldap.org/faq/data/cache/1140.html
-# - http://www.openldap.org/faq/data/cache/1133.html
-# - man 5 slapd.access
-#
-#
-########################################################################
-# Most common services: Postfix, Amavis, SASLauth, Dovecot
-# (Most used ACLs are cheaper when written first.)
-#
-# Postfix have read access to the attribute they need.
-olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        attrs=entry,objectClass,fvd,fvl,fripostMaildrop,fripostOptionalMaildrop,fripostLocalAlias
-        filter=(&(|(objectClass=FripostVirtualDomain)(objectClass=FripostVirtualUser)(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand))(!(objectClass=FripostPendingEntry))(!(fripostIsStatusActive=FALSE)))
-    by dn.exact="cn=Postfix,ou=services,o=mailHosting,dc=fripost,dc=org" =rsd
-    by users =0 break
-# Search lists and domain owners
-olcAccess: to dn.exact="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        attrs=entry
-    by dn.exact="cn=Postfix,ou=services,o=mailHosting,dc=fripost,dc=org" =s
-    by dn.exact="gidNumber=8+uidNumber=8,cn=peercred,cn=external,cn=auth" =s
-    by users =0 break
-#
-# Search domain owners / postmasters
-olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        attrs=entry,objectClass,fvd,fvl,fripostPostmaster,fripostOwner
-        filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry))(!(fripostIsStatusActive=FALSE)))
-    by dn.exact="gidNumber=8+uidNumber=8,cn=peercred,cn=external,cn=auth" =rsd
-    by users =0 break
-#
-# Anonymous can authenticate into the services. (But not read or write the password.)
-olcAccess: to dn.one="ou=services,o=mailHosting,dc=fripost,dc=org"
-        attrs=userPassword
-    by realanonymous =xd
-#
-# That's necessary for SASL proxy Authorize the web application.
-olcAccess: to dn.exact="cn=AdminWebPanel,ou=services,o=mailHosting,dc=fripost,dc=org"
-        attrs=entry,objectClass,authzTo
-    by realanonymous =x
-#
-# 1. The WebPanel itself cannot bind, read or write passwords. This
-# guarantees that, if an attacker gains its priviledge, it will *not* be
-# able to change user passwords (which would allow him/her to read every
-# emails). This is a trick to tackle the absence of 'realgroup'.
-# 2. Anonymous users can bind.
-# 3. Users can change their password (but not read it).
-# 4. The postmaster of a domain can change (replace) his/her users' password (but not read it).
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualUser)
-        attrs=userPassword
-    by realdn.exact="uid=AdminWebPanel@fripost.org,cn=auth" =0
-    by realanonymous =xd
-    by realself =w
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =w
-    by dn.onelevel="ou=managers,o=mailHosting,dc=fripost,dc=org" =w
-#
-# A catch-all, to be sure that noone else have access to the passwords.
-olcAccess: to dn.subtree="o=mailHosting,dc=fripost,dc=org"
-        attrs=userPassword
-    by * =0
-#
-#
-########################################################################
-# Virtual subtree, pending token and general access
-#
-# 1. Users need further access. We use a set to deny all access to non-users without
-# having a need for an expensive LDAP search (URL) in the AuthzTo.
-# /!\ The objectClass "FripostVirtualUser" is case-sensitive in this case!
-# 2,3. Services that need particular access on the tree.
-# 4. Managers have read/write access to the "virtual" subtree.
-olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-    by set.exact="user/objectClass & [FripostVirtualUser]" =0 break
-    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" =0 break
-    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =0 break
-    by dn.onelevel="ou=managers,o=mailHosting,dc=fripost,dc=org" =wrscd
-#
-# Only the domain Postmasters and Owners can delete the 'pending' status on domains.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(&(objectClass=FripostVirtualDomain)(objectClass=FripostPendingEntry))
-        attrs=objectClass val=FripostPendingEntry
-    by dnattr=fripostPostmaster =z break
-    by dnattr=fripostOwner =z break
-    by * =0 break
-#
-# The list creation service can delete the 'pending' status on lists and list commands.
-olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(&(|(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand))(objectClass=FripostPendingEntry))
-        attrs=objectClass val=FripostPendingEntry
-    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" =z break
-    by * +0 break
-#
-# ObjectClass is a public attribute: everyone can read and search it.
-olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        attrs=objectClass
-    by * +rscd
-#
-# The pending token is not public, but domain owner and postmasters can check their and
-# delete it (if the token matches, but the check is done on the library side).
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(&(objectClass=FripostVirtualDomain)(objectClass=FripostPendingEntry))
-        attrs=fripostPendingToken
-    by dnattr=fripostPostmaster =zcd break
-    by dnattr=fripostOwner =zcd break
-    by * +0 break
-#
-# The list creation service can delete the 'pending' status on lists and list commands.
-olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(&(|(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand))(objectClass=FripostPendingEntry))
-        attrs=fripostPendingToken
-    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" +z
-    by * +0
-#
-# The cleaning service can list the (expired) pending entries and delete them.
-olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(objectClass=FripostPendingEntry)
-        attrs=entry
-    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =zrd break
-    by * =0 break
-#
-# One can search search everywhere in the virtual tree.
-olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        attrs=entry
-    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" +s
-    by * =s break
-#
-# We're giving away create/delete access on the children attributes, but we will be carefull
-# with the 'entry' permissions.
-olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(objectClass=FripostVirtual)
-        attrs=children
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" =w
-    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =z
-olcAccess: to dn.one="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=children
-    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =z
-    by * break
-olcAccess: to dn.one="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry)))
-        attrs=children
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" =w
-#
-# The cleaning service needs to know when entries have been created.
-olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(objectClass=FripostPendingEntry)
-        attrs=createTimestamp
-    by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=org" =s
-#
-# Users can use these in filters (e.g., to list the entries they have created).
-olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(|(objectClass=FripostVirtualDomain)(objectClass=FripostVirtualUser)(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList))
-        attrs=fripostOwner,fripostPostmaster,fripostCanAddAlias,fripostCanAddList
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" =s break
-#
-#
-########################################################################
-# Virtual subtree, domains
-#
-# 1. The postmaster of a domain can give (or take back) people the right to create
-# aliases.
-# 2,3. People that can create aliases can list the members of the group.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=fripostCanAddAlias
-    by dnattr=fripostPostmaster =wrscd
-    by dnattr=fripostOwner =rscd
-    by set.exact="this/fripostCanAddAlias & (user | user/-1)" =rscd
-#
-# 1. The postmaster of a domain can give (or take back) people the right to create lists.
-# 2,3. People that can create lists can list the members of the group.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=fripostCanAddList
-    by dnattr=fripostPostmaster =wrscd
-    by dnattr=fripostOwner =rscd
-    by set.exact="this/fripostCanAddList & (user | user/-1)" =rscd
-#
-# 1-3. Noone (but the managers) can appoint domain Owners or Postmasters.
-# But people that can create aliases and lists can list the members of their group.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=fripostOwner,fripostPostmaster
-    by dnattr=fripostOwner =rscd
-    by dnattr=fripostPostmaster =rscd
-    by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" =rscd
-    by dn.onelevel,expand="$0" +d
-    by * +0
-#
-# 1. Domain owners can edit their entry's attributes.
-# 2. So can domain postmasters.
-# 3. Domain users can read the public domain attributes.
-# 4. So can users with "canAddAlias" or "canAddList" access.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=fvd,fripostIsStatusActive,description
-    by dnattr=fripostOwner =wrscd
-    by dnattr=fripostPostmaster =wrscd
-    by dn.onelevel,expand="$0" =rscd
-    by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" =rscd
-#
-# 1. Domain owners can edit their entry's attributes.
-# 2. So can domain postmasters.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=@fripostVirtualDomain
-    by dnattr=fripostOwner =wrscd
-    by dnattr=fripostPostmaster =wrscd
-    by * +0
-#
-# Users with "addDomain" access can create new entries, but only if
-# there is a pending token.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(&(objectClass=FripostVirtualDomain)(objectClass=FripostPendingEntry)(fripostPendingToken=*))
-        attrs=entry
-    by set.exact="this/-1/fripostCanAddDomain & (user | user/-1)" +a break
-    by * +0 break
-#
-# 1. Domain owners can delete their domain (and read the entry).
-# 2. So can domain postmasters.
-# 3. Domain users can read the domain entry (but not delete it).
-# 4. So can users with "canAddAlias" or "canAddList" rights.
-olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-        filter=(objectClass=FripostVirtualDomain)
-        attrs=entry
-    by dnattr=fripostOwner +zrd
-    by dnattr=fripostPostmaster +zrd
-    by dn.onelevel,expand="$0" +rd
-    by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" +rd
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +0
-#
-# Reserved local parts are reserved. /!\ The case must be insensitive
-# - postmaster: RFC 822, appendix C.6
-# - abuse:      RFC 2142, section 4
-olcAccess: to dn.regex="^fvl=(postmaster|abuse),fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org$"
-    by * =0
-#
-#
-########################################################################
-# Virtual subtree, users
-#
-# Users and their postmaster can read the quota (but not change it).
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualUser)
-        attrs=fripostUserQuota
-    by self =rscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =rscd
-#
-# 1. Users can modify their own entry.
-# 2. So can their postmasters.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualUser)
-        attrs=@FripostVirtualUser
-    by self =wrscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
-#
-# 1. Users can read their entry (but not delete it).
-# 2. Postmasters can create users (but not delete them).
-# (Provided that they have +a access to the parent's "children" attribute.)
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualUser)
-        attrs=entry
-    by self +rd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +ard
-#
-#
-########################################################################
-# Virtual subtree, aliases
-#
-# 1. The alias owner can list the ownership of the entry.
-# 2. The domain owner can add/delete/change the ownership of the entry.
-# 3. So can the domain postmasters.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualAlias)
-        attrs=fripostOwner
-    by dnattr=fripostOwner =rscd continue
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
-    by * +0
-#
-# 1. The alias owners can edit the rest of their entry's attributes.
-# 2. So can the domain owners.
-# 3. So can the domain postmasters.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualAlias)
-        attrs=@FripostVirtualAlias
-    by dnattr=fripostOwner =wrscd
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
-#
-# 1. The alias owners can read and delete the entry.
-# 2. So can the domain owner.
-# 3. So can the domain postmaster.
-# 4. Users with "canAddAlias" access (either explicitely, or as a wildcard) for the domain can create aliases for that domain.
-# (But *not* delete them, unless also owner.)
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualAlias)
-        attrs=entry
-    by dnattr=fripostOwner +zrd continue
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" +wrd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +wrd
-    by set.exact="this/-1/fripostCanAddAlias & (user | user/-1)" +a
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +0
-#
-#
-########################################################################
-# Virtual subtree, lists
-#
-# 1. The list owner can list the ownership of the entry.
-# 2. The domain owner can add/delete/change the ownership of the entry.
-# 3. So can the domain postmasters.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualList)
-        attrs=fripostOwner
-    by dnattr=fripostOwner =rscd continue
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
-    by * +0
-#
-# 1. The list owner read (but not edit) the transport-related attributes.
-# 2. So can the domain ower.
-# 3. So can the domain postmaster.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualList)
-        attrs=fripostListManager
-    by dnattr=fripostOwner =rscd
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" =rscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =rscd
-#
-# Local aliases are for internal use only.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualList)
-        attrs=fripostLocalAlias
-    by * =0
-#
-# 1. The list owners can edit their entry's attributes.
-# 2. So can the domain owners.
-# 3. So can the domain postmasters.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualList)
-        attrs=@FripostVirtualList
-    by dnattr=fripostOwner =wrscd
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" =wrscd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd
-#
-# 1. The domain owner can create and delete lists, but only those with a 'pending' status
-# 2. So can the domain postmaster.
-# 3. The list owner can delete pending lists.
-# 4. The entry creator can delete pending lists (needed to be able to rollback).
-# 5. People with "canAddList" access can create lists, but only with a 'pending' status.
-# 6. The list creation service can search and browse the entry.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(&(objectClass=FripostVirtualList)(objectClass=FripostPendingEntry))
-        attrs=entry
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" +w break
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +w break
-    by dnattr=fripostOwner +z continue
-    by dnattr=creatorsName +z continue
-    by set.exact="this/-1/fripostCanAddList & (user | user/-1)" +a break
-    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" +rd
-    by * +0 break
-#
-# 1. The domain owner can create and delete list commands, but only those with a 'pending' status
-# 2. So can the domain postmaster.
-# 3. The entry creator can delete pending list commands (needed to be able to rollback).
-# 4. People with "canAddList" access can create list commands, but only with a 'pending' status.
-# 5. The list creation service can search and browse the entry.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(&(objectClass=FripostVirtualListCommand)(objectClass=FripostPendingEntry))
-        attrs=entry
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" +w
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +w
-    by dnattr=creatorsName +z continue
-    by set.exact="this/-1/fripostCanAddList & (user | user/-1)" +a
-    by dn.exact="cn=CreateList,ou=services,o=mailHosting,dc=fripost,dc=org" +rd
-    by * +0
-#
-# 1. The list owners can read the entry.
-# 2. So can the domain's Owner.
-# 3. So can the domain's Postmaster.
-olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=org)$"
-        filter=(objectClass=FripostVirtualList)
-        attrs=entry
-    by dnattr=fripostOwner +rd
-    by group/FripostVirtualDomain/fripostOwner.expand="$1" +rd
-    by group/FripostVirtualDomain/fripostPostmaster.expand="$1" +rd
-    by * +0
-#
-#
-########################################################################
-# Catchall
-#
-# Users with "canAddDomain" access can see that they have the right
-# to create domains.
-olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(objectClass=FripostVirtual)
-        attrs=entry
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +rd
-olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-        filter=(objectClass=FripostVirtual)
-        attrs=fripostCanAddDomain
-    by set.exact="this/fripostCanAddDomain & (user | user/-1)" =rscd
-# Catch the break above
-olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=org"
-    by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org" +0
-# vim: set filetype=ldif :
diff --git a/vars.yml b/vars.yml
deleted file mode 100644
index 2cd3a42..0000000
--- a/vars.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-postfix_instance:
-  # The keys are the group names associated with a Postfix role, and the
-  # values are the name and group (optional) of the instance dedicated
-  # to that role.
-  IMAP:    { name: mda                }
-  MX:      { name: mta-in, group: mta }
-  MTA-out: { name: mta-out,group: mta }
-  MSA:     { name: msa                }
-- 
cgit v1.2.3