summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2013-11-29 22:41:56 +0100
committerGuilhem Moulin <guilhem@fripost.org>2015-06-07 02:50:58 +0200
commit89958abf4bc85a4e376cc68d98a721604af1ea77 (patch)
tree19b8930f0291518a0038e37fd605ed156a0bd21f
parent3d8b0ac104dee68b47d9a4d2ef622e7f1acdd7a4 (diff)
Allow flexible ACLs for SASL's EXTERNAL mechanism.
"username=postfix,cn=peercred,cn=external,cn=auth" is replaced by "gidNumber=106+uidNumber=102,cn=peercred,cn=external,cn=auth" where 102 is postfix's UID and 106 its primary GID (looked up from /etc/passwd).
-rw-r--r--lib/openldap31
-rw-r--r--roles/common-LDAP/templates/etc/ldap/database.ldif.j24
2 files changed, 32 insertions, 3 deletions
diff --git a/lib/openldap b/lib/openldap
index 5a4cef4..983299a 100644
--- a/lib/openldap
+++ b/lib/openldap
@@ -22,7 +22,7 @@ from ldap.dn import dn2str,explode_dn,str2dn
from ldap.modlist import addModlist
from ldif import LDIFParser
from functools import partial
-import re
+import re, pwd
# Dirty hack to check equality between the targetted LDIF and that
@@ -47,6 +47,28 @@ indexedDN = {
'olcHdbConfig': [('olcDbDirectory', '%s' )],
}
+# Allow for flexible ACLs for user using SASL's EXTERNAL mechanism.
+# "username=postfix,cn=peercred,cn=external,cn=auth" is replaced by
+# "gidNumber=106+uidNumber=102,cn=peercred,cn=external,cn=auth" where
+# 102 is postfix's UID and 106 its primary GID.
+# (Regular expressions are not allowed.)
+sasl_ext_re = re.compile( r"""(?P<start>\sby\s+dn(?:\.exact)?)=
+ (?P<quote>['\"]?)username=(?P<user>[a-z][-a-z0-9_]*),
+ (?P<end>cn=peercred,cn=external,cn=auth)
+ (?P=quote)\s"""
+ , re.VERBOSE )
+pwd_dict = {}
+
+def acl_sasl_ext(m):
+ u = m.group('user')
+ if u not in pwd_dict.keys():
+ pwd_dict[u] = pwd.getpwnam(u)
+ return '%s="gidNumber=%d+uidNumber=%d,%s" ' % ( m.group('start')
+ , pwd_dict[u].pw_gid
+ , pwd_dict[u].pw_uid
+ , m.group('end')
+ )
+
# Run the given callback on each DN seen. If its return value is not
# None, update the changed variable.
@@ -149,6 +171,11 @@ def processEntry(module, l, dn, entry):
# which is implicit
diff.append(( ldap.MOD_DELETE, a, None ))
elif a in indexedAttributes:
+ if a == 'olcAccess':
+ # replace "username=...,cn=peercred,cn=external,cn=auth"
+ # by a DN with proper gidNumber and uidNumber
+ entry[a] = map ( partial(re.sub, sasl_ext_re, acl_sasl_ext)
+ , entry[a] )
# add explicit indices in the entry from the LDIF
entry[a] = map( (lambda x: '{%d}%s' % x)
, zip(range(len(entry[a])),entry[a]) )
@@ -310,6 +337,8 @@ def main():
module.fail_json(rv=e.returncode, msg=e.output.rstrip())
except ldap.LDAPError, e:
module.fail_json(msg=e.args[0]['info'])
+ except KeyError, e:
+ module.fail_json(msg=str(e))
module.exit_json(changed=changed)
diff --git a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
index 19fcdd0..1970a99 100644
--- a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
+++ b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2
@@ -111,14 +111,14 @@ olcAccess: to dn.children="ou=virtual,o=mailHosting,dc=fripost,dc=org"
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 dn.exact="username=postfix,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 dn.exact="username=postfix,cn=peercred,cn=external,cn=auth" =rsd
by users =0 break
#
# Anonymous can authenticate into the services. (But not read or write the password.)