# Load this file with # # ldapmodify -Y EXTERNAL -H ldapi:/// -f acl.ldif # # It will remove existing ACLs, and add the following instead. Ensure # that it's indeed the database #1 that you want to amend: # # ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b "cn=config" "olcSuffix=o=mailHosting,dc=fripost,dc=dev" dn # # # /!\ ATTENTION! Every modification made to this file should be # /!\ implemented in 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 dn: olcDatabase={1}hdb,cn=config changetype: modify replace: olcAccess # # Services have read access to the attribute they need. We put this ACL # first as it's likely to be the most used. # TODO: for postfix, it'd be more efficient and more secure to SASL-bind # on a UNIX socket (EXTERNAL mechanism); wait for Postfix 2.8. # TODO: IMAP, SASLauth, Amavis # TODO: if possible, make use GSSAPI/EXTERNAL for the services. olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=entry,fvd,fvu,fva,fvl,fvlc,fripostMaildrop,fripostOptionalMaildrop,fripostLocalAlias filter=(|(objectClass=FripostVirtualDomain)(objectClass=FripostVirtualUser)(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand)) by dn.exact="cn=SMTP,ou=services,o=mailHosting,dc=fripost,dc=dev" =rsd by users =0 break # olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=objectClass,fripostPendingToken,fripostIsStatusActive filter=(|(objectClass=FripostVirtualDomain)(objectClass=FripostVirtualUser)(objectClass=FripostVirtualAlias)(objectClass=FripostVirtualList)(objectClass=FripostVirtualListCommand)) by dn.exact="cn=SMTP,ou=services,o=mailHosting,dc=fripost,dc=dev" =sd by users =0 break # #olcAccess: to dn.regex="^fvu=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" # attrs=entry,objectClass,fripostIsStatusActive,fripostPendingToken,fvu,@amavisAccount # filter=(&(objectClass=FripostVirtualUser)(objectClass=amavisAccount)(fripostIsStatusActive=TRUE)(fripostPendingToken=FALSE)) # by dn.exact="gidNumber=113+uidNumber=116,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=dev" attrs=userPassword by realanonymous =xd # # That's necessary for SASL proxy Authorize the web application. olcAccess: to dn.one="ou=services,o=mailHosting,dc=fripost,dc=dev" attrs=entry,objectClass,authzTo by realanonymous =x # # 1. Managers have read/write access to the "virtual" subtree. # 2. The list creator needs further access. # 3. Other services have no access other than the one above. # 4,5. Other users need further access. olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=dev" by dn.onelevel="ou=managers,o=mailHosting,dc=fripost,dc=dev" =wrscd by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =0 break by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=dev" =0 break by dn.onelevel="ou=services,o=mailHosting,dc=fripost,dc=dev" =0 by dn.regex="^fvu=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" =0 break by anonymous =0 break # # 1. Users can change their password (but not read it). # 2. Anonymous users can bind. # 3. Else, we inspect the 2 following ACLs. olcAccess: to dn.regex="^fvu=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" attrs=userPassword by realself =w by anonymous =xd by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" =0 break # # The postmaster of a domain can change (replace) his/her users' password (but not read it). olcAccess: to dn.regex="^fvu=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" filter=(objectClass=FripostVirtualUser) attrs=userPassword by group/fripostVirtualDomain/fripostPostmaster.expand="$1" =w # # No permission on the userPassword attribute for other users. # (That's a catch-all, just to be sure that services, etc. cannot read the passwords). olcAccess: to dn.subtree="o=mailHosting,dc=fripost,dc=dev" attrs=userPassword by * =0 # # 1. Users can search (e.g., to list the entries they have created). # 2. So can the list creator. olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=objectClass by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" =s by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =s by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=dev" =s # # 1. Users can search (e.g., to list the entries they have created). # 2. Additional permissions may be added later on. olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=entry,fripostOwner,fripostPostmaster,fripostCanAddAlias,fripostCanAddList by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" =s break by dn.onelevel="ou=services,o=mailHosting,dc=fripost,dc=dev" =0 break # # Noone may create children under a pending entry. This is important # since otherwise we couldn't delete old pending entries # non-recursively. olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" filter=(fripostPendingToken=*) attrs=children by * =0 # # Our service can list and delete (old) pending entries. olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" filter=(fripostPendingToken=*) attrs=entry by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=dev" =zrd break by dn.onelevel="ou=services,o=mailHosting,dc=fripost,dc=dev" +0 break by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 break # # Our service can search anywhere in the tree (for old pending entries). olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=entry by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" +0 break by dn.onelevel="ou=services,o=mailHosting,dc=fripost,dc=dev" +s by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 break # # Our service needs to have 'z' access on the 'children' of the parent of the entry that is # to be deleted. (And 'z' access of the 'entry' attribute of this entry.) olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=children by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=dev" =z by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =0 break by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 break # # Our service needs search access to list (old) pending entries. olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=dev" filter=(fripostPendingToken=*) attrs=createTimestamp,fripostPendingToken by dn.exact="cn=DeletePendingEntries,ou=services,o=mailHosting,dc=fripost,dc=dev" =sd by dn.onelevel="ou=services,o=mailHosting,dc=fripost,dc=dev" +0 break by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 break # # Everyone can create/delete domains. (Provided s/he has +a/+z access to the # "entry" attribute of the domains s/he wants to delete.) olcAccess: to dn.base="ou=virtual,o=mailHosting,dc=fripost,dc=dev" attrs=children by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" =w # # 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="^(fvu|fva|fvl)=(postmaster|abuse),fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" by * =0 # # Everyone can check for the non-presence of the 'pending' status. olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" filter=(&(objectClass=FripostVirtualDomain)(!(fripostPendingToken=*))) attrs=fripostPendingToken by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" =s # # Only the domain Postmasters and Owners can search the unlock token and delete the # 'pending' status (but not read). olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" filter=(objectClass=FripostVirtualDomain) attrs=fripostPendingToken by dnattr=fripostPostmaster =zscd by dnattr=fripostOwner =zscd # # 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=dev$" 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=dev$" 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=dev)$" 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="$1" +d by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +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=dev)$" filter=(objectClass=FripostVirtualDomain) attrs=fvd,fripostIsStatusActive,description by dnattr=fripostOwner =wrscd by dnattr=fripostPostmaster =wrscd by dn.onelevel,expand="$1" =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=dev$" filter=(objectClass=FripostVirtualDomain) attrs=@fripostVirtualDomain by dnattr=fripostOwner =wrscd by dnattr=fripostPostmaster =wrscd by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 # # Everyone can add or delete children, but we will be carefull with the # kid's "entry" attribute, which require +a and +z to add and delete # respectively. olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev$" filter=(objectClass=FripostVirtualDomain) attrs=children by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +w # # 1. Users with "addDomain" access can create new entries. # 2. Domain owners can delete their domain (and read the entry). # 3. So can domain postmasters. # 4. Domain users can read the domain entry (but not delete it). # 5. So can users with "canAddAlias" or "canAddList" rights. olcAccess: to dn.regex="^(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" filter=(objectClass=FripostVirtualDomain) attrs=entry by set.exact="this/-1/fripostCanAddDomain & (user | user/-1)" +a continue by dnattr=fripostOwner +zrd by dnattr=fripostPostmaster +zrd by dn.onelevel,expand="$1" +rd by set.exact="(this/fripostCanAddAlias | this/fripostCanAddList) & (user | user/-1)" +rd by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 # # Noone (but the managers) can change quotas. olcAccess: to dn.regex="^fvu=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" 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="^fvu=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" filter=(objectClass=FripostVirtualUser) attrs=@FripostVirtualUser by self =wrscd by group/fripostVirtualDomain/fripostPostmaster.expand="$1" =wrscd # # 1. Postmasters can create users (but not delete them). # (Provided that they have +a access to the parent's "children" attribute.) # 2. Users can read their entry (but not delete it). olcAccess: to dn.regex="^fvu=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" filter=(objectClass=FripostVirtualUser) attrs=entry by group/fripostVirtualDomain/fripostPostmaster.expand="$1" +ard by self +rd # # 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="^fva=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" 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 dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +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="^fva=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" 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="^fva=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" 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=dev" +0 # # 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=dev)$" 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 dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +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=dev)$" filter=(objectClass=FripostVirtualList) attrs=fripostListManager by dnattr=fripostOwner =rscd by group/fripostVirtualDomain/fripostOwner.expand="$1" =rscd by group/fripostVirtualDomain/fripostPostmaster.expand="$1" =rscd # # 1,2,3. The list owner and the domain Owner and Postmaster can search # (but not read) the 'pending' token. # 4. The list creator can remove the "pending" flag. # (We don't need to limit the search to presence only here, since when present the value is # always 'TRUE') olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" filter=(objectClass=FripostVirtualList) attrs=fripostPendingToken by dnattr=fripostOwner =scd by group/fripostVirtualDomain/fripostOwner.expand="$1" =scd by group/fripostVirtualDomain/fripostPostmaster.expand="$1" =scd by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =zsd # # 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=dev)$" 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 list owners can read the entry. # 2. So can the domain's Owner. # 3. So can the domain's Postmaster. # 4. Users with "canAddList" capability (either explicitely, or as a wildcard) for the domain can create lists for that domain. # (But *not* delete them, unless also owner.) # 6. The list creator can read the entry. olcAccess: to dn.regex="^fvl=[^,]+,(fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev)$" filter=(objectClass=FripostVirtualList) attrs=entry by dnattr=fripostOwner +rd continue by group/fripostVirtualDomain/fripostOwner.expand="$1" +rad by group/fripostVirtualDomain/fripostPostmaster.expand="$1" +rad by set.exact="this/-1/fripostCanAddList & (user | user/-1)" +a by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0 by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =rsd # # The List Creator can add list commands. olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev" filter=(objectClass=FripostVirtualList) attrs=children by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =a # # The List Creator can add list commands. olcAccess: to dn.regex="^fvlc=[^,]+,fvl=[^,]+,fvd=[^,]+,ou=virtual,o=mailHosting,dc=fripost,dc=dev" filter=(objectClass=FripostVirtualListCommand) attrs=entry by dn.exact="cn=ListCreator,ou=services,o=mailHosting,dc=fripost,dc=dev" =a # # Catch the "break" control above. olcAccess: to dn.subtree="ou=virtual,o=mailHosting,dc=fripost,dc=dev" by dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=dev" +0