s4:ldapcmp: cope with range retrivals of multivalued attributes
authorStefan Metzmacher <metze@samba.org>
Mon, 14 Feb 2011 13:18:14 +0000 (14:18 +0100)
committerStefan Metzmacher <metze@samba.org>
Mon, 14 Feb 2011 15:26:46 +0000 (16:26 +0100)
A Windows Server returns a 'member;range=0-1499' attribute
with the first 1500 values of the 'member' attribute.

The client can do a BASE search on the given object
and ask for the 'member;range=1500-*' attribute.
It needs to loop until the high part of the returned
range is '*'.

metze

Autobuild-User: Stefan Metzmacher <metze@samba.org>
Autobuild-Date: Mon Feb 14 16:26:46 CET 2011 on sn-devel-104

source4/scripting/python/samba/netcmd/ldapcmp.py

index 1cde860fb10da205a3e71ce1a1bbfe7291e86cd1..160aa312581514b4eb0df917765c56f1a2f2e0e3 100755 (executable)
@@ -133,6 +133,73 @@ class LDAPBase(object):
         except Ldb.LdbError, e:
             assert "No such object" in str(e)
 
+    def get_attribute_name(self, key):
+        """ Returns the real attribute name
+            It resolved ranged results e.g. member;range=0-1499
+        """
+
+        r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$")
+
+        m = r.match(key)
+        if m is None:
+            return key
+
+        return m.group(1)
+
+    def get_attribute_values(self, object_dn, key, vals):
+        """ Returns list with all attribute values
+            It resolved ranged results e.g. member;range=0-1499
+        """
+
+        r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$")
+
+        m = r.match(key)
+        if m is None:
+            # no range, just return the values
+            return vals
+
+        attr = m.group(1)
+        hi = int(m.group(3))
+
+        # get additional values in a loop
+        # until we get a response with '*' at the end
+        while True:
+
+            n = "%s;range=%d-*" % (attr, hi + 1)
+            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=[n])
+            assert len(res) == 1
+            res = dict(res[0])
+            del res["dn"]
+
+            fm = None
+            fvals = None
+
+            for key in res.keys():
+                m = r.match(key)
+
+                if m is None:
+                    continue
+
+                if m.group(1) != attr:
+                    continue
+
+                fm = m
+                fvals = list(res[key])
+                break
+
+            if fm is None:
+                break
+
+            vals.extend(fvals)
+            if fm.group(3) == "*":
+                # if we got "*" we're done
+                break
+
+            assert int(fm.group(2)) == hi + 1
+            hi = int(fm.group(3))
+
+        return vals
+
     def get_attributes(self, object_dn):
         """ Returns dict with all default visible attributes
         """
@@ -142,7 +209,11 @@ class LDAPBase(object):
         # 'Dn' element is not iterable and we have it as 'distinguishedName'
         del res["dn"]
         for key in res.keys():
-            res[key] = list(res[key])
+            vals = list(res[key])
+            del res[key]
+            name = self.get_attribute_name(key)
+            res[name] = self.get_attribute_values(object_dn, key, vals)
+
         return res
 
     def get_descriptor_sddl(self, object_dn):