diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2013-03-24 19:58:28 +0100 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2013-03-24 22:48:13 +0100 |
commit | d6a6e8b436fc2b3aabc8a6edd62ad60bd70e0c4c (patch) | |
tree | ac420f4f5b4dc2d3b2ffeae77d7abb7f695c0069 /pynslcd | |
parent | 41ba574974a22e709bde5728e90de5dd0c2ce82d (diff) |
Implement support for nested groups in pynslcd
Diffstat (limited to 'pynslcd')
-rw-r--r-- | pynslcd/common.py | 17 | ||||
-rw-r--r-- | pynslcd/group.py | 53 |
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): |