Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/pynslcd
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2013-03-24 19:58:28 +0100
committerArthur de Jong <arthur@arthurdejong.org>2013-03-24 22:48:13 +0100
commitd6a6e8b436fc2b3aabc8a6edd62ad60bd70e0c4c (patch)
treeac420f4f5b4dc2d3b2ffeae77d7abb7f695c0069 /pynslcd
parent41ba574974a22e709bde5728e90de5dd0c2ce82d (diff)
Implement support for nested groups in pynslcd
Diffstat (limited to 'pynslcd')
-rw-r--r--pynslcd/common.py17
-rw-r--r--pynslcd/group.py53
2 files changed, 54 insertions, 16 deletions
diff --git a/pynslcd/common.py b/pynslcd/common.py
index bbffef4..3a59cbe 100644
--- a/pynslcd/common.py
+++ b/pynslcd/common.py
@@ -82,18 +82,23 @@ class Request(object):
stream."""
pass
+ def get_results(self, parameters):
+ """Provide the result entries by performing a search."""
+ for dn, attributes in self.search(self.conn, parameters=parameters):
+ for values in self.convert(dn, attributes, parameters):
+ yield values
+
def handle_request(self, parameters):
"""This method handles the request based on the parameters read
with read_parameters()."""
try:
#with cache.con:
if True:
- for dn, attributes in self.search(self.conn, parameters=parameters):
- for values in self.convert(dn, attributes, parameters):
- self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
- self.write(*values)
- if self.cache:
- self.cache.store(*values)
+ for values in self.get_results(parameters):
+ self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
+ self.write(*values)
+ if self.cache:
+ self.cache.store(*values)
except ldap.SERVER_DOWN:
if self.cache:
logging.debug('read from cache')
diff --git a/pynslcd/group.py b/pynslcd/group.py
index a43aae5..20f81bf 100644
--- a/pynslcd/group.py
+++ b/pynslcd/group.py
@@ -22,6 +22,7 @@ import itertools
import logging
from ldap.filter import escape_filter_chars
+import ldap
from passwd import dn2uid, uid2dn
import cache
@@ -51,7 +52,7 @@ class Search(search.LDAPSearch):
def __init__(self, *args, **kwargs):
super(Search, self).__init__(*args, **kwargs)
- if 'memberUid' in self.parameters:
+ if 'memberUid' in self.parameters or 'member' in self.parameters:
# set up our own attributes that leave out membership attributes
self.attributes = list(self.attributes)
self.attributes.remove(attmap['memberUid'])
@@ -95,24 +96,39 @@ class GroupRequest(common.Request):
self.fp.write_int32(gid)
self.fp.write_stringlist(members)
- def convert(self, dn, attributes, parameters):
- # get group names and check against requested group name
- names = attributes['cn']
- # get group group password
- passwd = attributes['userPassword'][0]
- # get group id(s)
- gids = [int(x) for x in attributes['gidNumber']]
- # build member list
- members = set()
+ def get_members(self, attributes, members, subgroups, seen):
# add the memberUid values
for member in clean(attributes['memberUid']):
if common.isvalidname(member):
members.add(member)
# translate and add the member values
for memberdn in clean(attributes['member']):
+ if memberdn in seen:
+ continue
+ seen.add(memberdn)
member = dn2uid(self.conn, memberdn)
if member and common.isvalidname(member):
members.add(member)
+ else:
+ subgroups.append(memberdn)
+
+ def convert(self, dn, attributes, parameters):
+ # get group names and check against requested group name
+ names = attributes['cn']
+ # get group group password
+ passwd = attributes['userPassword'][0]
+ # get group id(s)
+ gids = [int(x) for x in attributes['gidNumber']]
+ # build member list
+ members = set()
+ subgroups = []
+ seen = set([dn])
+ self.get_members(attributes, members, subgroups, seen)
+ # go over subgroups to find more members
+ while subgroups:
+ memberdn = subgroups.pop(0)
+ for dn2, attributes2 in self.search(self.conn, base=memberdn, scope=ldap.SCOPE_BASE):
+ self.get_members(attributes2, members, subgroups, seen)
# actually return the results
for name in names:
if not common.isvalidname(name):
@@ -150,6 +166,23 @@ class GroupByMemberRequest(GroupRequest):
common.validate_name(memberuid)
return dict(memberUid=memberuid)
+ def get_results(self, parameters):
+ seen = set()
+ for dn, attributes in self.search(self.conn, parameters=parameters):
+ seen.add(dn)
+ for values in self.convert(dn, attributes, parameters):
+ yield values
+ tocheck = list(seen)
+ # find parent groups
+ while tocheck:
+ group = tocheck.pop(0)
+ for dn, attributes in self.search(self.conn, parameters=dict(member=group)):
+ if dn not in seen:
+ seen.add(dn)
+ tocheck.append(dn)
+ for result in self.convert(dn, attributes, parameters):
+ yield result
+
class GroupAllRequest(GroupRequest):