s4:ldap.py - add more "objectGUID" related tests
[nivanova/samba-autobuild/.git] / source4 / dsdb / tests / python / ldap.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
4
5 import optparse
6 import sys
7 import time
8 import base64
9 import os
10
11 sys.path.append("bin/python")
12 import samba
13 samba.ensure_external_module("testtools", "testtools")
14 samba.ensure_external_module("subunit", "subunit/python")
15
16 import samba.getopt as options
17
18 from samba.auth import system_session
19 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
20 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
21 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
22 from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX
23 from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INVALID_ATTRIBUTE_SYNTAX
24 from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN
25 from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
26 from ldb import Message, MessageElement, Dn
27 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
28 from ldb import timestring
29 from samba import Ldb
30 from samba.dsdb import (UF_NORMAL_ACCOUNT,
31     UF_WORKSTATION_TRUST_ACCOUNT,
32     UF_PASSWD_NOTREQD, UF_ACCOUNTDISABLE, ATYPE_NORMAL_ACCOUNT,
33     ATYPE_WORKSTATION_TRUST, SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE,
34     SYSTEM_FLAG_CONFIG_ALLOW_RENAME, SYSTEM_FLAG_CONFIG_ALLOW_MOVE,
35     SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE)
36
37 from subunit.run import SubunitTestRunner
38 import unittest
39
40 from samba.ndr import ndr_pack, ndr_unpack
41 from samba.dcerpc import security
42
43 parser = optparse.OptionParser("ldap.py [options] <host>")
44 sambaopts = options.SambaOptions(parser)
45 parser.add_option_group(sambaopts)
46 parser.add_option_group(options.VersionOptions(parser))
47 # use command line creds if available
48 credopts = options.CredentialsOptions(parser)
49 parser.add_option_group(credopts)
50 opts, args = parser.parse_args()
51
52 if len(args) < 1:
53     parser.print_usage()
54     sys.exit(1)
55
56 host = args[0]
57
58 lp = sambaopts.get_loadparm()
59 creds = credopts.get_credentials(lp)
60
61 class BasicTests(unittest.TestCase):
62
63     def delete_force(self, ldb, dn):
64         try:
65             ldb.delete(dn)
66         except LdbError, (num, _):
67             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
68
69     def find_basedn(self, ldb):
70         res = ldb.search(base="", expression="", scope=SCOPE_BASE,
71                          attrs=["defaultNamingContext"])
72         self.assertEquals(len(res), 1)
73         return res[0]["defaultNamingContext"][0]
74
75     def find_configurationdn(self, ldb):
76         res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["configurationNamingContext"])
77         self.assertEquals(len(res), 1)
78         return res[0]["configurationNamingContext"][0]
79
80     def find_schemadn(self, ldb):
81         res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
82         self.assertEquals(len(res), 1)
83         return res[0]["schemaNamingContext"][0]
84
85     def find_domain_sid(self):
86         res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
87         return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
88
89     def set_dsheuristics(self, dsheuristics):
90         m = Message()
91         m.dn = Dn(self.ldb, "CN=Directory Service, CN=Windows NT, CN=Services, "
92                   + self.configuration_dn)
93         if dsheuristics is not None:
94             m["dSHeuristics"] = MessageElement(dsheuristics, FLAG_MOD_REPLACE,
95                                                "dSHeuristics")
96         else:
97             m["dSHeuristics"] = MessageElement([], FLAG_MOD_DELETE, "dsHeuristics")
98         self.ldb.modify(m)
99
100     def setUp(self):
101         super(BasicTests, self).setUp()
102         self.ldb = ldb
103         self.gc_ldb = gc_ldb
104         self.base_dn = self.find_basedn(ldb)
105         self.configuration_dn = self.find_configurationdn(ldb)
106         self.schema_dn = self.find_schemadn(ldb)
107         self.domain_sid = self.find_domain_sid()
108
109         print "baseDN: %s\n" % self.base_dn
110
111         self.delete_force(self.ldb, "cn=posixuser,cn=users," + self.base_dn)
112         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
113         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
114         self.delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
115         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
116         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
117         self.delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
118         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
119         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
120         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
121         self.delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
122         self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
123         self.delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
124         self.delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
125         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
126         self.delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
127         self.delete_force(self.ldb, "cn=parentguidtest,cn=users," + self.base_dn)
128         self.delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
129         self.delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
130         self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
131         self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
132         self.delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn)
133         self.delete_force(self.ldb, "cn=testsecret,cn=system," + self.base_dn)
134
135     def test_objectclasses(self):
136         """Test objectClass behaviour"""
137         print "Test objectClass behaviour"""
138
139         # We cannot create LSA-specific objects (oc "secret" or "trustedDomain")
140         try:
141             self.ldb.add({
142                 "dn": "cn=testsecret,cn=system," + self.base_dn,
143                 "objectClass": "secret" })
144             self.fail()
145         except LdbError, (num, _):
146             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
147
148         # Invalid objectclass specified
149         try:
150             self.ldb.add({
151                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
152                 "objectClass": [] })
153             self.fail()
154         except LdbError, (num, _):
155             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
156
157         # Invalid objectclass specified
158         try:
159             self.ldb.add({
160                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
161                 "objectClass": "X" })
162             self.fail()
163         except LdbError, (num, _):
164             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
165
166         # Invalid objectCategory specified
167         try:
168             self.ldb.add({
169                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
170                 "objectClass": "person",
171                 "objectCategory": self.base_dn })
172             self.fail()
173         except LdbError, (num, _):
174             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
175
176         # Multi-valued "systemFlags"
177         try:
178             self.ldb.add({
179                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
180                 "objectClass": "person",
181                 "systemFlags": ["0", str(SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE)] })
182             self.fail()
183         except LdbError, (num, _):
184             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
185
186         # We cannot instanciate from an abstract objectclass
187         try:
188             self.ldb.add({
189                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
190                 "objectClass": "connectionPoint" })
191             self.fail()
192         except LdbError, (num, _):
193             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
194
195         # Test allowed system flags
196         self.ldb.add({
197              "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
198              "objectClass": "person",
199              "systemFlags": str(~(SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE)) })
200
201         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
202                          scope=SCOPE_BASE, attrs=["systemFlags"])
203         self.assertTrue(len(res) == 1)
204         self.assertEquals(res[0]["systemFlags"][0], "0")
205
206         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
207
208         self.ldb.add({
209              "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
210              "objectClass": "person" })
211
212         # We can remove derivation classes of the structural objectclass
213         # but they're going to be readded afterwards
214         m = Message()
215         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
216         m["objectClass"] = MessageElement("top", FLAG_MOD_DELETE,
217           "objectClass")
218         ldb.modify(m)
219
220         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
221                          scope=SCOPE_BASE, attrs=["objectClass"])
222         self.assertTrue(len(res) == 1)
223         self.assertTrue("top" in res[0]["objectClass"])
224
225         # The top-most structural class cannot be deleted since there are
226         # attributes of it in use
227         m = Message()
228         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
229         m["objectClass"] = MessageElement("person", FLAG_MOD_DELETE,
230           "objectClass")
231         try:
232             ldb.modify(m)
233             self.fail()
234         except LdbError, (num, _):
235             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
236
237         # We cannot delete classes which weren't specified
238         m = Message()
239         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
240         m["objectClass"] = MessageElement("computer", FLAG_MOD_DELETE,
241           "objectClass")
242         try:
243             ldb.modify(m)
244             self.fail()
245         except LdbError, (num, _):
246             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
247
248         # An invalid class cannot be added
249         m = Message()
250         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
251         m["objectClass"] = MessageElement("X", FLAG_MOD_ADD,
252           "objectClass")
253         try:
254             ldb.modify(m)
255             self.fail()
256         except LdbError, (num, _):
257             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
258
259         # The top-most structural class cannot be changed by adding another
260         # structural one
261         m = Message()
262         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
263         m["objectClass"] = MessageElement("user", FLAG_MOD_ADD,
264           "objectClass")
265         try:
266             ldb.modify(m)
267             self.fail()
268         except LdbError, (num, _):
269             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
270
271         # An already specified objectclass cannot be added another time
272         m = Message()
273         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
274         m["objectClass"] = MessageElement("person", FLAG_MOD_ADD,
275           "objectClass")
276         try:
277             ldb.modify(m)
278             self.fail()
279         except LdbError, (num, _):
280             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
281
282         # Auxiliary classes can always be added
283         m = Message()
284         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
285         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_ADD,
286           "objectClass")
287         ldb.modify(m)
288
289         # It's only possible to replace with the same objectclass combination.
290         # So the replace action on "objectClass" attributes is really useless.
291         m = Message()
292         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
293         m["objectClass"] = MessageElement(["top", "person", "bootableDevice"],
294           FLAG_MOD_REPLACE, "objectClass")
295         ldb.modify(m)
296
297         m = Message()
298         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
299         m["objectClass"] = MessageElement(["person", "bootableDevice"],
300           FLAG_MOD_REPLACE, "objectClass")
301         ldb.modify(m)
302
303         m = Message()
304         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
305         m["objectClass"] = MessageElement(["top", "person", "bootableDevice",
306           "connectionPoint"], FLAG_MOD_REPLACE, "objectClass")
307         try:
308             ldb.modify(m)
309             self.fail()
310         except LdbError, (num, _):
311             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
312
313         # We cannot remove all object classes by an empty replace
314         m = Message()
315         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
316         m["objectClass"] = MessageElement([], FLAG_MOD_REPLACE, "objectClass")
317         try:
318             ldb.modify(m)
319             self.fail()
320         except LdbError, (num, _):
321             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
322
323         m = Message()
324         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
325         m["objectClass"] = MessageElement(["top", "computer"], FLAG_MOD_REPLACE,
326           "objectClass")
327         try:
328             ldb.modify(m)
329             self.fail()
330         except LdbError, (num, _):
331             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
332
333         # Classes can be removed unless attributes of them are used.
334         m = Message()
335         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
336         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
337           "objectClass")
338         ldb.modify(m)
339
340         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
341                          scope=SCOPE_BASE, attrs=["objectClass"])
342         self.assertTrue(len(res) == 1)
343         self.assertFalse("bootableDevice" in res[0]["objectClass"])
344
345         m = Message()
346         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
347         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_ADD,
348           "objectClass")
349         ldb.modify(m)
350
351         # Add an attribute specific to the "bootableDevice" class
352         m = Message()
353         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
354         m["bootParameter"] = MessageElement("test", FLAG_MOD_ADD,
355           "bootParameter")
356         ldb.modify(m)
357
358         # Classes can be removed unless attributes of them are used. Now there
359         # exist such attributes on the entry.
360         m = Message()
361         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
362         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
363           "objectClass")
364         try:
365             ldb.modify(m)
366             self.fail()
367         except LdbError, (num, _):
368             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
369
370         # Remove the previously specified attribute
371         m = Message()
372         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
373         m["bootParameter"] = MessageElement("test", FLAG_MOD_DELETE,
374           "bootParameter")
375         ldb.modify(m)
376
377         # Classes can be removed unless attributes of them are used.
378         m = Message()
379         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
380         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
381           "objectClass")
382         ldb.modify(m)
383
384         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
385
386     def test_system_only(self):
387         """Test systemOnly objects"""
388         print "Test systemOnly objects"""
389
390         try:
391             self.ldb.add({
392                 "dn": "cn=ldaptestobject," + self.base_dn,
393                 "objectclass": "configuration"})
394             self.fail()
395         except LdbError, (num, _):
396             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
397
398         try:
399             self.ldb.add({
400                 "dn": "cn=testsecret,cn=system," + self.base_dn,
401                 "objectclass": "secret"})
402             self.fail()
403         except LdbError, (num, _):
404             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
405
406         self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
407         self.delete_force(self.ldb, "cn=testsecret,cn=system," + self.base_dn)
408
409         try:
410             self.ldb.add({
411                 "dn": "cn=ldaptestcontainer," + self.base_dn,
412                 "objectclass": "container",
413                 "isCriticalSystemObject": "TRUE"})
414             self.fail()
415         except LdbError, (num, _):
416             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
417
418         self.ldb.add({
419             "dn": "cn=ldaptestcontainer," + self.base_dn,
420             "objectclass": "container"})
421
422         m = Message()
423         m.dn = Dn(ldb, "cn=ldaptestcontainer," + self.base_dn)
424         m["isCriticalSystemObject"] = MessageElement("TRUE", FLAG_MOD_REPLACE,
425           "isCriticalSystemObject")
426         try:
427             ldb.modify(m)
428             self.fail()
429         except LdbError, (num, _):
430             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
431
432         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
433
434         # Proof if DC SAM object has "isCriticalSystemObject" set
435         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["serverName"])
436         self.assertTrue(len(res) == 1)
437         self.assertTrue("serverName" in res[0])
438         res = self.ldb.search(res[0]["serverName"][0], scope=SCOPE_BASE,
439                               attrs=["serverReference"])
440         self.assertTrue(len(res) == 1)
441         self.assertTrue("serverReference" in res[0])
442         res = self.ldb.search(res[0]["serverReference"][0], scope=SCOPE_BASE,
443                               attrs=["isCriticalSystemObject"])
444         self.assertTrue(len(res) == 1)
445         self.assertTrue("isCriticalSystemObject" in res[0])
446         self.assertEquals(res[0]["isCriticalSystemObject"][0], "TRUE")
447
448     def test_invalid_parent(self):
449         """Test adding an object with invalid parent"""
450         print "Test adding an object with invalid parent"""
451
452         try:
453             self.ldb.add({
454                 "dn": "cn=ldaptestgroup,cn=thisdoesnotexist123,"
455                    + self.base_dn,
456                 "objectclass": "group"})
457             self.fail()
458         except LdbError, (num, _):
459             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
460
461         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=thisdoesnotexist123,"
462           + self.base_dn)
463
464         try:
465             self.ldb.add({
466                 "dn": "ou=testou,cn=users," + self.base_dn,
467                 "objectclass": "organizationalUnit"})
468             self.fail()
469         except LdbError, (num, _):
470             self.assertEquals(num, ERR_NAMING_VIOLATION)
471
472         self.delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn)
473
474     def test_invalid_attribute(self):
475         """Test invalid attributes on schema/objectclasses"""
476         print "Test invalid attributes on schema/objectclasses"""
477
478         # attributes not in schema test
479
480         # add operation
481
482         try:
483             self.ldb.add({
484                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
485                 "objectclass": "group",
486                 "thisdoesnotexist": "x"})
487             self.fail()
488         except LdbError, (num, _):
489             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
490
491         self.ldb.add({
492              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
493              "objectclass": "group"})
494
495         # modify operation
496
497         m = Message()
498         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
499         m["thisdoesnotexist"] = MessageElement("x", FLAG_MOD_REPLACE,
500           "thisdoesnotexist")
501         try:
502             ldb.modify(m)
503             self.fail()
504         except LdbError, (num, _):
505             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
506
507         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
508
509         # attributes not in objectclasses and mandatory attributes missing test
510         # Use here a non-SAM entry since it doesn't have special triggers
511         # associated which have an impact on the error results.
512
513         # add operations
514
515         # mandatory attribute missing
516         try:
517             self.ldb.add({
518                 "dn": "cn=ldaptestobject," + self.base_dn,
519                 "objectclass": "ipProtocol"})
520             self.fail()
521         except LdbError, (num, _):
522             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
523
524         # inadequate but schema-valid attribute specified
525         try:
526             self.ldb.add({
527                 "dn": "cn=ldaptestobject," + self.base_dn,
528                 "objectclass": "ipProtocol",
529                 "ipProtocolNumber": "1",
530                 "uid" : "0"})
531             self.fail()
532         except LdbError, (num, _):
533             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
534
535         self.ldb.add({
536             "dn": "cn=ldaptestobject," + self.base_dn,
537             "objectclass": "ipProtocol",
538             "ipProtocolNumber": "1"})
539
540         # modify operations
541
542         # inadequate but schema-valid attribute add trial
543         m = Message()
544         m.dn = Dn(ldb, "cn=ldaptestobject," + self.base_dn)
545         m["uid"] = MessageElement("0", FLAG_MOD_ADD, "uid")
546         try:
547             ldb.modify(m)
548             self.fail()
549         except LdbError, (num, _):
550             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
551
552         # mandatory attribute delete trial
553         m = Message()
554         m.dn = Dn(ldb, "cn=ldaptestobject," + self.base_dn)
555         m["ipProtocolNumber"] = MessageElement([], FLAG_MOD_DELETE,
556           "ipProtocolNumber")
557         try:
558             ldb.modify(m)
559             self.fail()
560         except LdbError, (num, _):
561             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
562
563         # mandatory attribute delete trial
564         m = Message()
565         m.dn = Dn(ldb, "cn=ldaptestobject," + self.base_dn)
566         m["ipProtocolNumber"] = MessageElement([], FLAG_MOD_REPLACE,
567           "ipProtocolNumber")
568         try:
569             ldb.modify(m)
570             self.fail()
571         except LdbError, (num, _):
572             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
573
574         self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
575
576     def test_single_valued_attributes(self):
577         """Test single-valued attributes"""
578         print "Test single-valued attributes"""
579
580         try:
581             self.ldb.add({
582                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
583                 "objectclass": "group",
584                 "sAMAccountName": ["nam1", "nam2"]})
585             self.fail()
586         except LdbError, (num, _):
587             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
588
589         self.ldb.add({
590              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
591              "objectclass": "group"})
592
593         m = Message()
594         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
595         m["sAMAccountName"] = MessageElement(["nam1","nam2"], FLAG_MOD_REPLACE,
596           "sAMAccountName")
597         try:
598             ldb.modify(m)
599             self.fail()
600         except LdbError, (num, _):
601             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
602
603         m = Message()
604         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
605         m["sAMAccountName"] = MessageElement("testgroupXX", FLAG_MOD_REPLACE,
606           "sAMAccountName")
607         ldb.modify(m)
608
609         m = Message()
610         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
611         m["sAMAccountName"] = MessageElement("testgroupXX2", FLAG_MOD_ADD,
612           "sAMAccountName")
613         try:
614             ldb.modify(m)
615             self.fail()
616         except LdbError, (num, _):
617             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
618
619         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
620
621     def test_description_attribute(self):
622         """Test description attribute"""
623         print "Test description attribute"""
624
625         self.ldb.add({
626             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
627             "description": "desc2",
628             "objectclass": "group",
629             "description": "desc1"})
630
631         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
632                          scope=SCOPE_BASE, attrs=["description"])
633         self.assertTrue(len(res) == 1)
634         self.assertTrue("description" in res[0])
635         self.assertTrue(len(res[0]["description"]) == 1)
636         self.assertEquals(res[0]["description"][0], "desc1")
637
638         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
639
640         self.ldb.add({
641             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
642             "objectclass": "group",
643             "description": ["desc1", "desc2"]})
644
645         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
646                          scope=SCOPE_BASE, attrs=["description"])
647         self.assertTrue(len(res) == 1)
648         self.assertTrue("description" in res[0])
649         self.assertTrue(len(res[0]["description"]) == 2)
650         self.assertTrue(res[0]["description"][0] == "desc1" or
651                         res[0]["description"][1] == "desc1")
652         self.assertTrue(res[0]["description"][0] == "desc2" or
653                         res[0]["description"][1] == "desc2")
654
655         m = Message()
656         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
657         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
658           "description")
659         try:
660             ldb.modify(m)
661             self.fail()
662         except LdbError, (num, _):
663             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
664
665         m = Message()
666         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
667         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
668           "description")
669         ldb.modify(m)
670
671         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
672
673         self.ldb.add({
674             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
675             "objectclass": "group" })
676
677         m = Message()
678         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
679         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
680           "description")
681         ldb.modify(m)
682
683         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
684                          scope=SCOPE_BASE, attrs=["description"])
685         self.assertTrue(len(res) == 1)
686         self.assertTrue("description" in res[0])
687         self.assertTrue(len(res[0]["description"]) == 1)
688         self.assertEquals(res[0]["description"][0], "desc1")
689
690         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
691
692         self.ldb.add({
693             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
694             "objectclass": "group",
695             "description": ["desc1", "desc2"]})
696
697         m = Message()
698         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
699         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
700           "description")
701         ldb.modify(m)
702
703         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
704                          scope=SCOPE_BASE, attrs=["description"])
705         self.assertTrue(len(res) == 1)
706         self.assertTrue("description" in res[0])
707         self.assertTrue(len(res[0]["description"]) == 1)
708         self.assertEquals(res[0]["description"][0], "desc1")
709
710         m = Message()
711         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
712         m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
713           "description")
714         try:
715             ldb.modify(m)
716             self.fail()
717         except LdbError, (num, _):
718             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
719
720         m = Message()
721         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
722         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
723           "description")
724         try:
725             ldb.modify(m)
726             self.fail()
727         except LdbError, (num, _):
728             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
729
730         m = Message()
731         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
732         m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
733           "description")
734         ldb.modify(m)
735         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
736                          scope=SCOPE_BASE, attrs=["description"])
737         self.assertTrue(len(res) == 1)
738         self.assertFalse("description" in res[0])
739
740         m = Message()
741         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
742         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
743           "description")
744         try:
745             ldb.modify(m)
746             self.fail()
747         except LdbError, (num, _):
748             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
749
750         m = Message()
751         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
752         m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
753           "description")
754         try:
755             ldb.modify(m)
756             self.fail()
757         except LdbError, (num, _):
758             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
759
760         m = Message()
761         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
762         m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
763           "description")
764         ldb.modify(m)
765
766         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
767                          scope=SCOPE_BASE, attrs=["description"])
768         self.assertTrue(len(res) == 1)
769         self.assertTrue("description" in res[0])
770         self.assertTrue(len(res[0]["description"]) == 1)
771         self.assertEquals(res[0]["description"][0], "desc1")
772
773         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
774
775     def test_attribute_ranges(self):
776         """Test attribute ranges"""
777         print "Test attribute ranges"""
778
779         # Too short (min. 1)
780         try:
781             ldb.add({
782                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
783                "objectClass": "person",
784                "sn": "" })
785             self.fail()
786         except LdbError, (num, _):
787             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
788
789         # Too long (max. 64)
790 #        try:
791 #            ldb.add({
792 #               "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
793 #               "objectClass": "person",
794 #               "sn": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" })
795 #            self.fail()
796 #        except LdbError, (num, _):
797 #            self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
798
799         ldb.add({
800            "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
801            "objectClass": "person" })
802
803         # Too short (min. 1)
804         m = Message()
805         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
806         m["sn"] = MessageElement("", FLAG_MOD_REPLACE, "sn")
807         try:
808             ldb.modify(m)
809             self.fail()
810         except LdbError, (num, _):
811             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
812
813         # Too long (max. 64)
814 #        m = Message()
815 #        m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
816 #        m["sn"] = MessageElement("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", FLAG_MOD_REPLACE, "sn")
817 #        try:
818 #            ldb.modify(m)
819 #            self.fail()
820 #        except LdbError, (num, _):
821 #            self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
822
823         m = Message()
824         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
825         m["sn"] = MessageElement("x", FLAG_MOD_REPLACE, "sn")
826         ldb.modify(m)
827
828         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
829
830     def test_empty_messages(self):
831         """Test empty messages"""
832         print "Test empty messages"""
833
834         m = Message()
835         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
836
837         try:
838             ldb.add(m)
839             self.fail()
840         except LdbError, (num, _):
841             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
842
843         try:
844             ldb.modify(m)
845             self.fail()
846         except LdbError, (num, _):
847             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
848
849         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
850
851     def test_empty_attributes(self):
852         """Test empty attributes"""
853         print "Test empty attributes"""
854
855         m = Message()
856         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
857         m["objectClass"] = MessageElement("group", FLAG_MOD_ADD, "objectClass")
858         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
859
860         try:
861             ldb.add(m)
862             self.fail()
863         except LdbError, (num, _):
864             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
865
866         self.ldb.add({
867             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
868             "objectclass": "group"})
869
870         m = Message()
871         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
872         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
873
874         try:
875             ldb.modify(m)
876             self.fail()
877         except LdbError, (num, _):
878             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
879
880         m = Message()
881         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
882         m["description"] = MessageElement([], FLAG_MOD_REPLACE, "description")
883         ldb.modify(m)
884
885         m = Message()
886         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
887         m["description"] = MessageElement([], FLAG_MOD_DELETE, "description")
888         try:
889             ldb.modify(m)
890             self.fail()
891         except LdbError, (num, _):
892             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
893
894         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
895
896     def test_instanceType(self):
897         """Tests the 'instanceType' attribute"""
898         print "Tests the 'instanceType' attribute"""
899
900         # The instance type is single-valued
901         try:
902             self.ldb.add({
903                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
904                 "objectclass": "group",
905                 "instanceType": ["0", "1"]})
906             self.fail()
907         except LdbError, (num, _):
908             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
909
910         # The head NC flag cannot be set without the write flag
911         try:
912             self.ldb.add({
913                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
914                 "objectclass": "group",
915                 "instanceType": "1" })
916             self.fail()
917         except LdbError, (num, _):
918             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
919
920         # We cannot manipulate NCs without the head NC flag
921         try:
922             self.ldb.add({
923                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
924                 "objectclass": "group",
925                 "instanceType": "32" })
926             self.fail()
927         except LdbError, (num, _):
928             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
929
930         self.ldb.add({
931              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
932              "objectclass": "group"})
933
934         m = Message()
935         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
936         m["instanceType"] = MessageElement("0", FLAG_MOD_REPLACE,
937           "instanceType")
938         try:
939             ldb.modify(m)
940             self.fail()
941         except LdbError, (num, _):
942             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
943
944         m = Message()
945         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
946         m["instanceType"] = MessageElement([], FLAG_MOD_REPLACE,
947           "instanceType")
948         try:
949             ldb.modify(m)
950             self.fail()
951         except LdbError, (num, _):
952             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
953
954         m = Message()
955         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
956         m["instanceType"] = MessageElement([], FLAG_MOD_DELETE, "instanceType")
957         try:
958             ldb.modify(m)
959             self.fail()
960         except LdbError, (num, _):
961             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
962
963         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
964
965     def test_distinguished_name(self):
966         """Tests the 'distinguishedName' attribute"""
967         print "Tests the 'distinguishedName' attribute"""
968
969         # The "dn" shortcut isn't supported
970         m = Message()
971         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
972         m["objectClass"] = MessageElement("group", 0, "objectClass")
973         m["dn"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn, 0,
974           "dn")
975         try:
976             ldb.add(m)
977             self.fail()
978         except LdbError, (num, _):
979             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
980
981         # a wrong "distinguishedName" attribute is obviously tolerated
982         self.ldb.add({
983               "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
984               "objectclass": "group",
985               "distinguishedName": "cn=ldaptest,cn=users," + self.base_dn})
986
987         # proof if the DN has been set correctly
988         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
989                          scope=SCOPE_BASE, attrs=["distinguishedName"])
990         self.assertTrue(len(res) == 1)
991         self.assertTrue("distinguishedName" in res[0])
992         self.assertTrue(Dn(ldb, res[0]["distinguishedName"][0])
993            == Dn(ldb, "cn=ldaptestgroup, cn=users," + self.base_dn))
994
995         # The "dn" shortcut isn't supported
996         m = Message()
997         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
998         m["dn"] = MessageElement(
999           "cn=ldaptestgroup,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
1000           "dn")
1001         try:
1002             ldb.modify(m)
1003             self.fail()
1004         except LdbError, (num, _):
1005             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
1006
1007         m = Message()
1008         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1009         m["distinguishedName"] = MessageElement(
1010           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_ADD,
1011           "distinguishedName")
1012
1013         try:
1014             ldb.modify(m)
1015             self.fail()
1016         except LdbError, (num, _):
1017             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1018
1019         m = Message()
1020         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1021         m["distinguishedName"] = MessageElement(
1022           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
1023           "distinguishedName")
1024
1025         try:
1026             ldb.modify(m)
1027             self.fail()
1028         except LdbError, (num, _):
1029             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1030
1031         m = Message()
1032         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1033         m["distinguishedName"] = MessageElement(
1034           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_DELETE,
1035           "distinguishedName")
1036
1037         try:
1038             ldb.modify(m)
1039             self.fail()
1040         except LdbError, (num, _):
1041             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1042
1043         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1044
1045     def test_rdn_name(self):
1046         """Tests the RDN"""
1047         print "Tests the RDN"""
1048
1049         try:
1050             self.ldb.add({
1051                  "dn": "description=xyz,cn=users," + self.base_dn,
1052                  "objectclass": "group"})
1053             self.fail()
1054         except LdbError, (num, _):
1055             self.assertEquals(num, ERR_NAMING_VIOLATION)
1056
1057         self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
1058
1059         # a wrong "name" attribute is obviously tolerated
1060         self.ldb.add({
1061              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1062              "objectclass": "group",
1063              "name": "ldaptestgroupx"})
1064
1065         # proof if the name has been set correctly
1066         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1067                          scope=SCOPE_BASE, attrs=["name"])
1068         self.assertTrue(len(res) == 1)
1069         self.assertTrue("name" in res[0])
1070         self.assertTrue(res[0]["name"][0] == "ldaptestgroup")
1071
1072         m = Message()
1073         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1074         m["name"] = MessageElement("cn=ldaptestuser", FLAG_MOD_REPLACE,
1075           "name")
1076         try:
1077             ldb.modify(m)
1078             self.fail()
1079         except LdbError, (num, _):
1080             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
1081
1082         m = Message()
1083         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1084         m["cn"] = MessageElement("ldaptestuser",
1085           FLAG_MOD_REPLACE, "cn")
1086         try:
1087             ldb.modify(m)
1088             self.fail()
1089         except LdbError, (num, _):
1090             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
1091
1092         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1093
1094
1095         # this test needs to be disabled until we really understand
1096         # what the rDN length constraints are
1097     def DISABLED_test_largeRDN(self):
1098         """Testing large rDN (limit 64 characters)"""
1099         rdn = "CN=a012345678901234567890123456789012345678901234567890123456789012";
1100         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1101         ldif = """
1102 dn: %s,%s""" % (rdn,self.base_dn) + """
1103 objectClass: container
1104 """
1105         self.ldb.add_ldif(ldif)
1106         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1107
1108         rdn = "CN=a0123456789012345678901234567890123456789012345678901234567890120";
1109         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1110         try:
1111             ldif = """
1112 dn: %s,%s""" % (rdn,self.base_dn) + """
1113 objectClass: container
1114 """
1115             self.ldb.add_ldif(ldif)
1116             self.fail()
1117         except LdbError, (num, _):
1118             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1119         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1120
1121     def test_rename(self):
1122         """Tests the rename operation"""
1123         print "Tests the rename operations"""
1124
1125         try:
1126             # cannot rename to be a child of itself
1127             ldb.rename(self.base_dn, "dc=test," + self.base_dn)
1128             self.fail()
1129         except LdbError, (num, _):
1130             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1131
1132         try:
1133             # inexistent object
1134             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1135             self.fail()
1136         except LdbError, (num, _):
1137             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1138
1139         self.ldb.add({
1140              "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
1141              "objectclass": "user" })
1142
1143         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1144         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
1145         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestUSER3,cn=users," + self.base_dn)
1146
1147         try:
1148             # containment problem: a user entry cannot contain user entries
1149             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser4,cn=ldaptestuser3,cn=users," + self.base_dn)
1150             self.fail()
1151         except LdbError, (num, _):
1152             self.assertEquals(num, ERR_NAMING_VIOLATION)
1153
1154         try:
1155             # invalid parent
1156             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=people,cn=users," + self.base_dn)
1157             self.fail()
1158         except LdbError, (num, _):
1159             self.assertEquals(num, ERR_OTHER)
1160
1161         try:
1162             # invalid target DN syntax
1163             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, ",cn=users," + self.base_dn)
1164             self.fail()
1165         except LdbError, (num, _):
1166             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1167
1168         try:
1169             # invalid RDN name
1170             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "ou=ldaptestuser3,cn=users," + self.base_dn)
1171             self.fail()
1172         except LdbError, (num, _):
1173             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1174
1175         self.delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
1176
1177         # Performs some "systemFlags" testing
1178
1179         # Move failing since no "SYSTEM_FLAG_CONFIG_ALLOW_MOVE"
1180         try:
1181             ldb.rename("CN=DisplaySpecifiers," + self.configuration_dn, "CN=DisplaySpecifiers,CN=Services," + self.configuration_dn)
1182             self.fail()
1183         except LdbError, (num, _):
1184             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1185
1186         # Limited move failing since no "SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE"
1187         try:
1188             ldb.rename("CN=Directory Service,CN=Windows NT,CN=Services," + self.configuration_dn, "CN=Directory Service,CN=RRAS,CN=Services," + self.configuration_dn)
1189             self.fail()
1190         except LdbError, (num, _):
1191             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1192
1193         # Rename failing since no "SYSTEM_FLAG_CONFIG_ALLOW_RENAME"
1194         try:
1195             ldb.rename("CN=DisplaySpecifiers," + self.configuration_dn, "CN=DisplaySpecifiers2," + self.configuration_dn)
1196             self.fail()
1197         except LdbError, (num, _):
1198             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1199
1200         # It's not really possible to test moves on the schema partition since
1201         # there don't exist subcontainers on it.
1202
1203         # Rename failing since "SYSTEM_FLAG_SCHEMA_BASE_OBJECT"
1204         try:
1205             ldb.rename("CN=Top," + self.schema_dn, "CN=Top2," + self.schema_dn)
1206             self.fail()
1207         except LdbError, (num, _):
1208             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1209
1210         # Move failing since "SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE"
1211         try:
1212             ldb.rename("CN=Users," + self.base_dn, "CN=Users,CN=Computers," + self.base_dn)
1213             self.fail()
1214         except LdbError, (num, _):
1215             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1216
1217         # Rename failing since "SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME"
1218         try:
1219             ldb.rename("CN=Users," + self.base_dn, "CN=Users2," + self.base_dn)
1220             self.fail()
1221         except LdbError, (num, _):
1222             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1223
1224         # Performs some other constraints testing
1225
1226         try:
1227             ldb.rename("CN=Policies,CN=System," + self.base_dn, "CN=Users2," + self.base_dn)
1228             self.fail()
1229         except LdbError, (num, _):
1230             self.assertEquals(num, ERR_OTHER)
1231
1232     def test_rename_twice(self):
1233         """Tests the rename operation twice - this corresponds to a past bug"""
1234         print "Tests the rename twice operation"""
1235
1236         self.ldb.add({
1237              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
1238              "objectclass": "user" })
1239
1240         ldb.rename("cn=ldaptestuser5,cn=users," + self.base_dn, "cn=ldaptestUSER5,cn=users," + self.base_dn)
1241         self.delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
1242         self.ldb.add({
1243              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
1244              "objectclass": "user" })
1245         ldb.rename("cn=ldaptestuser5,cn=Users," + self.base_dn, "cn=ldaptestUSER5,cn=users," + self.base_dn)
1246         res = ldb.search(expression="cn=ldaptestuser5")
1247         print "Found %u records" % len(res)
1248         self.assertEquals(len(res), 1, "Wrong number of hits for cn=ldaptestuser5")
1249         res = ldb.search(expression="(&(cn=ldaptestuser5)(objectclass=user))")
1250         print "Found %u records" % len(res)
1251         self.assertEquals(len(res), 1, "Wrong number of hits for (&(cn=ldaptestuser5)(objectclass=user))")
1252         self.delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
1253
1254     def test_objectGUID(self):
1255         """Test objectGUID behaviour"""
1256         print "Testing objectGUID behaviour\n"
1257
1258         # The objectGUID cannot directly be set
1259         try:
1260             self.ldb.add_ldif("""
1261 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1262 objectClass: container
1263 objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
1264 """)
1265             self.fail()
1266         except LdbError, (num, _):
1267             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1268
1269         self.ldb.add({
1270             "dn": "cn=ldaptestcontainer," + self.base_dn,
1271             "objectClass": "container" })
1272
1273         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1274                          scope=SCOPE_BASE,
1275                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
1276         self.assertTrue(len(res) == 1)
1277         self.assertTrue("objectGUID" in res[0])
1278         self.assertTrue("uSNCreated" in res[0])
1279         self.assertTrue("uSNChanged" in res[0])
1280         self.assertTrue("whenCreated" in res[0])
1281         self.assertTrue("whenChanged" in res[0])
1282
1283         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1284
1285         # All the following attributes are specificable on add operations
1286         self.ldb.add({
1287             "dn": "cn=ldaptestcontainer," + self.base_dn,
1288             "objectClass": "container",
1289             "uSNCreated" : "1",
1290             "uSNChanged" : "1",
1291             "whenCreated": timestring(long(time.time())),
1292             "whenChanged": timestring(long(time.time())) })
1293
1294         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1295                          scope=SCOPE_BASE,
1296                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
1297         self.assertTrue(len(res) == 1)
1298         self.assertTrue("objectGUID" in res[0])
1299         self.assertTrue("uSNCreated" in res[0])
1300         self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
1301         self.assertTrue("uSNChanged" in res[0])
1302         self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
1303
1304         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1305
1306         # All this attributes are specificable on add operations
1307         self.ldb.add({
1308             "dn": "cn=ldaptestcontainer," + self.base_dn,
1309             "objectclass": "container",
1310             "uSNCreated" : "1",
1311             "uSNChanged" : "1",
1312             "whenCreated": timestring(long(time.time())),
1313             "whenChanged": timestring(long(time.time())) })
1314
1315         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1316                          scope=SCOPE_BASE,
1317                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
1318         self.assertTrue(len(res) == 1)
1319         self.assertTrue("objectGUID" in res[0])
1320         self.assertTrue("uSNCreated" in res[0])
1321         self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
1322         self.assertTrue("uSNChanged" in res[0])
1323         self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
1324         self.assertTrue("whenCreated" in res[0])
1325         self.assertTrue("whenChanged" in res[0])
1326
1327         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1328
1329     def test_parentGUID(self):
1330         """Test parentGUID behaviour"""
1331         print "Testing parentGUID behaviour\n"
1332
1333         self.ldb.add({
1334             "dn": "cn=parentguidtest,cn=users," + self.base_dn,
1335             "objectclass":"user",
1336             "samaccountname":"parentguidtest"});
1337         res1 = ldb.search(base="cn=parentguidtest,cn=users," + self.base_dn, scope=SCOPE_BASE,
1338                           attrs=["parentGUID", "samaccountname"]);
1339         res2 = ldb.search(base="cn=users," + self.base_dn,scope=SCOPE_BASE,
1340                           attrs=["objectGUID"]);
1341         res3 = ldb.search(base=self.base_dn, scope=SCOPE_BASE,
1342                           attrs=["parentGUID"]);
1343         res4 = ldb.search(base=self.configuration_dn, scope=SCOPE_BASE,
1344                           attrs=["parentGUID"]);
1345         res5 = ldb.search(base=self.schema_dn, scope=SCOPE_BASE,
1346                           attrs=["parentGUID"]);
1347
1348         """Check if the parentGUID is valid """
1349         self.assertEquals(res1[0]["parentGUID"], res2[0]["objectGUID"]);
1350
1351         """Check if it returns nothing when there is no parent object - default NC"""
1352         has_parentGUID = False
1353         for key in res3[0].keys():
1354             if key == "parentGUID":
1355                 has_parentGUID = True
1356                 break
1357         self.assertFalse(has_parentGUID);
1358
1359         """Check if it returns nothing when there is no parent object - configuration NC"""
1360         has_parentGUID = False
1361         for key in res4[0].keys():
1362             if key == "parentGUID":
1363                 has_parentGUID = True
1364                 break
1365         self.assertFalse(has_parentGUID);
1366
1367         """Check if it returns nothing when there is no parent object - schema NC"""
1368         has_parentGUID = False
1369         for key in res5[0].keys():
1370             if key == "parentGUID":
1371                 has_parentGUID = True
1372                 break
1373         self.assertFalse(has_parentGUID);
1374
1375         """Ensures that if you look for another object attribute after the constructed
1376             parentGUID, it will return correctly"""
1377         has_another_attribute = False
1378         for key in res1[0].keys():
1379             if key == "sAMAccountName":
1380                 has_another_attribute = True
1381                 break
1382         self.assertTrue(has_another_attribute)
1383         self.assertTrue(len(res1[0]["samaccountname"]) == 1)
1384         self.assertEquals(res1[0]["samaccountname"][0], "parentguidtest");
1385
1386         print "Testing parentGUID behaviour on rename\n"
1387
1388         self.ldb.add({
1389             "dn": "cn=testotherusers," + self.base_dn,
1390             "objectclass":"container"});
1391         res1 = ldb.search(base="cn=testotherusers," + self.base_dn,scope=SCOPE_BASE,
1392                           attrs=["objectGUID"]);
1393         ldb.rename("cn=parentguidtest,cn=users," + self.base_dn,
1394                    "cn=parentguidtest,cn=testotherusers," + self.base_dn);
1395         res2 = ldb.search(base="cn=parentguidtest,cn=testotherusers," + self.base_dn,
1396                           scope=SCOPE_BASE,
1397                           attrs=["parentGUID"]);
1398         self.assertEquals(res1[0]["objectGUID"], res2[0]["parentGUID"]);
1399
1400         self.delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
1401         self.delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
1402
1403     def test_groupType_int32(self):
1404         """Test groupType (int32) behaviour (should appear to be casted to a 32 bit signed integer before comparsion)"""
1405         print "Testing groupType (int32) behaviour\n"
1406
1407         res1 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
1408                           attrs=["groupType"], expression="groupType=2147483653");
1409
1410         res2 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
1411                           attrs=["groupType"], expression="groupType=-2147483643");
1412
1413         self.assertEquals(len(res1), len(res2))
1414
1415         self.assertTrue(res1.count > 0)
1416
1417         self.assertEquals(res1[0]["groupType"][0], "-2147483643")
1418
1419     def test_linked_attributes(self):
1420         """This tests the linked attribute behaviour"""
1421         print "Testing linked attribute behaviour\n"
1422
1423         ldb.add({
1424             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1425             "objectclass": "group"})
1426
1427         # This should not work since "memberOf" is linked to "member"
1428         try:
1429             ldb.add({
1430                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1431                 "objectclass": "user",
1432                 "memberOf": "cn=ldaptestgroup,cn=users," + self.base_dn})
1433         except LdbError, (num, _):
1434             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1435
1436         ldb.add({
1437             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1438             "objectclass": "user"})
1439
1440         m = Message()
1441         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1442         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1443           FLAG_MOD_ADD, "memberOf")
1444         try:
1445             ldb.modify(m)
1446             self.fail()
1447         except LdbError, (num, _):
1448             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1449
1450         m = Message()
1451         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1452         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
1453           FLAG_MOD_ADD, "member")
1454         ldb.modify(m)
1455
1456         m = Message()
1457         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1458         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1459           FLAG_MOD_REPLACE, "memberOf")
1460         try:
1461             ldb.modify(m)
1462             self.fail()
1463         except LdbError, (num, _):
1464             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1465
1466         m = Message()
1467         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1468         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1469           FLAG_MOD_DELETE, "memberOf")
1470         try:
1471             ldb.modify(m)
1472             self.fail()
1473         except LdbError, (num, _):
1474             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1475
1476         m = Message()
1477         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1478         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
1479           FLAG_MOD_DELETE, "member")
1480         ldb.modify(m)
1481
1482         # This should yield no results since the member attribute for
1483         # "ldaptestuser" should have been deleted
1484         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
1485                           scope=SCOPE_BASE,
1486                           expression="(member=cn=ldaptestuser,cn=users," + self.base_dn + ")",
1487                           attrs=[])
1488         self.assertTrue(len(res1) == 0)
1489
1490         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1491
1492         ldb.add({
1493             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1494             "objectclass": "group",
1495             "member": "cn=ldaptestuser,cn=users," + self.base_dn})
1496
1497         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1498
1499         # Make sure that the "member" attribute for "ldaptestuser" has been
1500         # removed
1501         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1502                           scope=SCOPE_BASE, attrs=["member"])
1503         self.assertTrue(len(res) == 1)
1504         self.assertFalse("member" in res[0])
1505
1506         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1507
1508     def test_wkguid(self):
1509         """Test Well known GUID behaviours (including DN+Binary)"""
1510         print "Test Well known GUID behaviours (including DN+Binary)"""
1511
1512         res = self.ldb.search(base=("<WKGUID=ab1d30f3768811d1aded00c04fd8d5cd,%s>" % self.base_dn), scope=SCOPE_BASE, attrs=[])
1513         self.assertEquals(len(res), 1)
1514
1515         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd:%s" % res[0].dn))
1516         self.assertEquals(len(res2), 1)
1517
1518         # Prove that the matching rule is over the whole DN+Binary
1519         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd"))
1520         self.assertEquals(len(res2), 0)
1521         # Prove that the matching rule is over the whole DN+Binary
1522         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=%s") % res[0].dn)
1523         self.assertEquals(len(res2), 0)
1524
1525     def test_subschemasubentry(self):
1526         """Test subSchemaSubEntry appears when requested, but not when not requested"""
1527         print "Test subSchemaSubEntry"""
1528
1529         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["subSchemaSubEntry"])
1530         self.assertEquals(len(res), 1)
1531         self.assertEquals(res[0]["subSchemaSubEntry"][0], "CN=Aggregate,"+self.schema_dn)
1532
1533         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["*"])
1534         self.assertEquals(len(res), 1)
1535         self.assertTrue("subScheamSubEntry" not in res[0])
1536
1537     def test_all(self):
1538         """Basic tests"""
1539
1540         print "Testing user add"
1541
1542         ldb.add({
1543             "dn": "cn=ldaptestuser,cn=uSers," + self.base_dn,
1544             "objectclass": "user",
1545             "cN": "LDAPtestUSER",
1546             "givenname": "ldap",
1547             "sn": "testy"})
1548
1549         ldb.add({
1550             "dn": "cn=ldaptestgroup,cn=uSers," + self.base_dn,
1551             "objectclass": "group",
1552             "member": "cn=ldaptestuser,cn=useRs," + self.base_dn})
1553
1554         ldb.add({
1555             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1556             "objectclass": "computer",
1557             "cN": "LDAPtestCOMPUTER"})
1558
1559         ldb.add({"dn": "cn=ldaptest2computer,cn=computers," + self.base_dn,
1560             "objectClass": "computer",
1561             "cn": "LDAPtest2COMPUTER",
1562             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT),
1563             "displayname": "ldap testy"})
1564
1565         try:
1566             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1567                      "objectClass": "computer",
1568                      "cn": "LDAPtest2COMPUTER"
1569                      })
1570             self.fail()
1571         except LdbError, (num, _):
1572             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1573
1574         try:
1575             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1576                      "objectClass": "computer",
1577                      "cn": "ldaptestcomputer3",
1578                      "sAMAccountType": str(ATYPE_NORMAL_ACCOUNT)
1579                 })
1580             self.fail()
1581         except LdbError, (num, _):
1582             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1583
1584         ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1585                  "objectClass": "computer",
1586                  "cn": "LDAPtestCOMPUTER3"
1587                  })
1588
1589         print "Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))";
1590         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestcomputer3)(objectClass=user))");
1591         self.assertEquals(len(res), 1, "Found only %d for (&(cn=ldaptestcomputer3)(objectClass=user))" % len(res))
1592
1593         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer3,CN=Computers," + self.base_dn));
1594         self.assertEquals(res[0]["cn"][0], "ldaptestcomputer3");
1595         self.assertEquals(res[0]["name"][0], "ldaptestcomputer3");
1596         self.assertEquals(res[0]["objectClass"][0], "top");
1597         self.assertEquals(res[0]["objectClass"][1], "person");
1598         self.assertEquals(res[0]["objectClass"][2], "organizationalPerson");
1599         self.assertEquals(res[0]["objectClass"][3], "user");
1600         self.assertEquals(res[0]["objectClass"][4], "computer");
1601         self.assertTrue("objectGUID" in res[0])
1602         self.assertTrue("whenCreated" in res[0])
1603         self.assertEquals(res[0]["objectCategory"][0], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn));
1604         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513);
1605         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT);
1606         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE);
1607
1608         self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
1609
1610         print "Testing attribute or value exists behaviour"
1611         try:
1612             ldb.modify_ldif("""
1613 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1614 changetype: modify
1615 replace: servicePrincipalName
1616 servicePrincipalName: host/ldaptest2computer
1617 servicePrincipalName: host/ldaptest2computer
1618 servicePrincipalName: cifs/ldaptest2computer
1619 """)
1620             self.fail()
1621         except LdbError, (num, msg):
1622             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
1623
1624         ldb.modify_ldif("""
1625 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1626 changetype: modify
1627 replace: servicePrincipalName
1628 servicePrincipalName: host/ldaptest2computer
1629 servicePrincipalName: cifs/ldaptest2computer
1630 """)
1631         try:
1632             ldb.modify_ldif("""
1633 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1634 changetype: modify
1635 add: servicePrincipalName
1636 servicePrincipalName: host/ldaptest2computer
1637 """)
1638             self.fail()
1639         except LdbError, (num, msg):
1640             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
1641
1642         print "Testing ranged results"
1643         ldb.modify_ldif("""
1644 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1645 changetype: modify
1646 replace: servicePrincipalName
1647 """)
1648
1649         ldb.modify_ldif("""
1650 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1651 changetype: modify
1652 add: servicePrincipalName
1653 servicePrincipalName: host/ldaptest2computer0
1654 servicePrincipalName: host/ldaptest2computer1
1655 servicePrincipalName: host/ldaptest2computer2
1656 servicePrincipalName: host/ldaptest2computer3
1657 servicePrincipalName: host/ldaptest2computer4
1658 servicePrincipalName: host/ldaptest2computer5
1659 servicePrincipalName: host/ldaptest2computer6
1660 servicePrincipalName: host/ldaptest2computer7
1661 servicePrincipalName: host/ldaptest2computer8
1662 servicePrincipalName: host/ldaptest2computer9
1663 servicePrincipalName: host/ldaptest2computer10
1664 servicePrincipalName: host/ldaptest2computer11
1665 servicePrincipalName: host/ldaptest2computer12
1666 servicePrincipalName: host/ldaptest2computer13
1667 servicePrincipalName: host/ldaptest2computer14
1668 servicePrincipalName: host/ldaptest2computer15
1669 servicePrincipalName: host/ldaptest2computer16
1670 servicePrincipalName: host/ldaptest2computer17
1671 servicePrincipalName: host/ldaptest2computer18
1672 servicePrincipalName: host/ldaptest2computer19
1673 servicePrincipalName: host/ldaptest2computer20
1674 servicePrincipalName: host/ldaptest2computer21
1675 servicePrincipalName: host/ldaptest2computer22
1676 servicePrincipalName: host/ldaptest2computer23
1677 servicePrincipalName: host/ldaptest2computer24
1678 servicePrincipalName: host/ldaptest2computer25
1679 servicePrincipalName: host/ldaptest2computer26
1680 servicePrincipalName: host/ldaptest2computer27
1681 servicePrincipalName: host/ldaptest2computer28
1682 servicePrincipalName: host/ldaptest2computer29
1683 """)
1684
1685         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE,
1686                          attrs=["servicePrincipalName;range=0-*"])
1687         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1688         #print len(res[0]["servicePrincipalName;range=0-*"])
1689         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
1690
1691         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
1692         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1693             # print res[0]["servicePrincipalName;range=0-19"].length
1694         self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
1695
1696
1697         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
1698         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1699         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
1700
1701         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
1702         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1703         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
1704
1705         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
1706         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1707         self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
1708
1709
1710         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
1711         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1712         self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
1713         # pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
1714
1715         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
1716         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1717         self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
1718             # print res[0]["servicePrincipalName;range=11-*"][18]
1719             # print pos_11
1720             # self.assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11)
1721
1722         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
1723         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1724         self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
1725             # self.assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11)
1726
1727         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
1728         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1729             # print res[0]["servicePrincipalName"][18]
1730             # print pos_11
1731         self.assertEquals(len(res[0]["servicePrincipalName"]), 30)
1732             # self.assertEquals(res[0]["servicePrincipalName"][18], pos_11)
1733
1734         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
1735         ldb.add({
1736             "dn": "cn=ldaptestuser2,cn=useRs," + self.base_dn,
1737             "objectClass": "user",
1738             "cn": "LDAPtestUSER2",
1739             "givenname": "testy",
1740             "sn": "ldap user2"})
1741
1742         print "Testing Ambigious Name Resolution"
1743         # Testing ldb.search for (&(anr=ldap testy)(objectClass=user))
1744         res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))")
1745         self.assertEquals(len(res), 3, "Found only %d of 3 for (&(anr=ldap testy)(objectClass=user))" % len(res))
1746
1747         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
1748         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
1749         self.assertEquals(len(res), 2, "Found only %d of 2 for (&(anr=testy ldap)(objectClass=user))" % len(res))
1750
1751         # Testing ldb.search for (&(anr=ldap)(objectClass=user))
1752         res = ldb.search(expression="(&(anr=ldap)(objectClass=user))")
1753         self.assertEquals(len(res), 4, "Found only %d of 4 for (&(anr=ldap)(objectClass=user))" % len(res))
1754
1755         # Testing ldb.search for (&(anr==ldap)(objectClass=user))
1756         res = ldb.search(expression="(&(anr==ldap)(objectClass=user))")
1757         self.assertEquals(len(res), 1, "Could not find (&(anr==ldap)(objectClass=user)). Found only %d for (&(anr=ldap)(objectClass=user))" % len(res))
1758
1759         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1760         self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1761         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
1762
1763         # Testing ldb.search for (&(anr=testy)(objectClass=user))
1764         res = ldb.search(expression="(&(anr=testy)(objectClass=user))")
1765         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res))
1766
1767         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
1768         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
1769         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res))
1770
1771         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
1772 # this test disabled for the moment, as anr with == tests are not understood
1773 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
1774 #        self.assertEquals(len(res), 1, "Found only %d for (&(anr==testy ldap)(objectClass=user))" % len(res))
1775
1776 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1777 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1778 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
1779
1780         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
1781 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
1782 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap)(objectClass=user))")
1783
1784 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1785 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1786 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
1787
1788         # Testing ldb.search for (&(anr=testy ldap user)(objectClass=user))
1789         res = ldb.search(expression="(&(anr=testy ldap user)(objectClass=user))")
1790         self.assertEquals(len(res), 1, "Could not find (&(anr=testy ldap user)(objectClass=user))")
1791
1792         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1793         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1794         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1795
1796         # Testing ldb.search for (&(anr==testy ldap user2)(objectClass=user))
1797 #        res = ldb.search(expression="(&(anr==testy ldap user2)(objectClass=user))")
1798 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap user2)(objectClass=user))")
1799
1800         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1801         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1802         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1803
1804         # Testing ldb.search for (&(anr==ldap user2)(objectClass=user))
1805 #        res = ldb.search(expression="(&(anr==ldap user2)(objectClass=user))")
1806 #        self.assertEquals(len(res), 1, "Could not find (&(anr==ldap user2)(objectClass=user))")
1807
1808         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1809         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1810         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1811
1812         # Testing ldb.search for (&(anr==not ldap user2)(objectClass=user))
1813 #        res = ldb.search(expression="(&(anr==not ldap user2)(objectClass=user))")
1814 #        self.assertEquals(len(res), 0, "Must not find (&(anr==not ldap user2)(objectClass=user))")
1815
1816         # Testing ldb.search for (&(anr=not ldap user2)(objectClass=user))
1817         res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))")
1818         self.assertEquals(len(res), 0, "Must not find (&(anr=not ldap user2)(objectClass=user))")
1819
1820         # Testing ldb.search for (&(anr="testy ldap")(objectClass=user)) (ie, with quotes)
1821 #        res = ldb.search(expression="(&(anr==\"testy ldap\")(objectClass=user))")
1822 #        self.assertEquals(len(res), 0, "Found (&(anr==\"testy ldap\")(objectClass=user))")
1823
1824         print "Testing Renames"
1825
1826         attrs = ["objectGUID", "objectSid"]
1827         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
1828         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
1829         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
1830
1831         # Check rename works with extended/alternate DN forms
1832         ldb.rename("<SID=" + ldb.schema_format_value("objectSID", res_user[0]["objectSID"][0]) + ">" , "cn=ldaptestUSER3,cn=users," + self.base_dn)
1833
1834         print "Testing ldb.search for (&(cn=ldaptestuser3)(objectClass=user))"
1835         res = ldb.search(expression="(&(cn=ldaptestuser3)(objectClass=user))")
1836         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser3)(objectClass=user))")
1837
1838         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1839         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1840         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1841
1842          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"
1843         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
1844         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
1845
1846         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1847         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1848         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1849
1850          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"
1851         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
1852         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
1853
1854         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1855         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1856         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1857
1858          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"
1859         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
1860         self.assertEquals(len(res), 0, "(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
1861
1862         # This is a Samba special, and does not exist in real AD
1863         #    print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1864         #    res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1865         #    if (res.error != 0 || len(res) != 1) {
1866         #        print "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1867         #        self.assertEquals(len(res), 1)
1868         #    }
1869         #    self.assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1870         #    self.assertEquals(res[0].cn, "ldaptestUSER3")
1871         #    self.assertEquals(res[0].name, "ldaptestUSER3")
1872
1873         print "Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1874         res = ldb.search(expression="(distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1875         self.assertEquals(len(res), 1, "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1876         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1877         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1878         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1879
1880         # ensure we cannot add it again
1881         try:
1882             ldb.add({"dn": "cn=ldaptestuser3,cn=userS," + self.base_dn,
1883                       "objectClass": "user",
1884                       "cn": "LDAPtestUSER3"})
1885             self.fail()
1886         except LdbError, (num, _):
1887             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
1888
1889         # rename back
1890         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1891
1892         # ensure we cannot rename it twice
1893         try:
1894             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn,
1895                        "cn=ldaptestuser2,cn=users," + self.base_dn)
1896             self.fail()
1897         except LdbError, (num, _):
1898             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1899
1900         # ensure can now use that name
1901         ldb.add({"dn": "cn=ldaptestuser3,cn=users," + self.base_dn,
1902                       "objectClass": "user",
1903                       "cn": "LDAPtestUSER3"})
1904
1905         # ensure we now cannot rename
1906         try:
1907             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
1908             self.fail()
1909         except LdbError, (num, _):
1910             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
1911         try:
1912             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=configuration," + self.base_dn)
1913             self.fail()
1914         except LdbError, (num, _):
1915             self.assertTrue(num in (71, 64))
1916
1917         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser5,cn=users," + self.base_dn)
1918
1919         ldb.delete("cn=ldaptestuser5,cn=users," + self.base_dn)
1920
1921         self.delete_force(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1922
1923         ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1924
1925         print "Testing subtree renames"
1926
1927         ldb.add({"dn": "cn=ldaptestcontainer," + self.base_dn,
1928                  "objectClass": "container"})
1929
1930         ldb.add({"dn": "CN=ldaptestuser4,CN=ldaptestcontainer," + self.base_dn,
1931                  "objectClass": "user",
1932                  "cn": "LDAPtestUSER4"})
1933
1934         ldb.modify_ldif("""
1935 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1936 changetype: modify
1937 add: member
1938 member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
1939 member: cn=ldaptestcomputer,cn=computers,""" + self.base_dn + """
1940 member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """
1941 """)
1942
1943         print "Testing ldb.rename of cn=ldaptestcontainer," + self.base_dn + " to cn=ldaptestcontainer2," + self.base_dn
1944         ldb.rename("CN=ldaptestcontainer," + self.base_dn, "CN=ldaptestcontainer2," + self.base_dn)
1945
1946         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user))"
1947         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))")
1948         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user))")
1949
1950         print "Testing subtree ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
1951         try:
1952             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1953                     expression="(&(cn=ldaptestuser4)(objectClass=user))",
1954                     scope=SCOPE_SUBTREE)
1955             self.fail(res)
1956         except LdbError, (num, _):
1957             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1958
1959         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
1960         try:
1961             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1962                     expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_ONELEVEL)
1963             self.fail()
1964         except LdbError, (num, _):
1965             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1966
1967         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in renamed container"
1968         res = ldb.search("cn=ldaptestcontainer2," + self.base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_SUBTREE)
1969         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user)) under cn=ldaptestcontainer2," + self.base_dn)
1970
1971         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
1972         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1973
1974         time.sleep(4)
1975
1976         print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"
1977         res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE)
1978         self.assertEquals(len(res), 1, "Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)), perhaps linked attributes are not consistant with subtree renames?")
1979
1980         print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn
1981         try:
1982             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn)
1983             self.fail()
1984         except LdbError, (num, _):
1985             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1986
1987         print "Testing ldb.rename (into non-existent container) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn
1988         try:
1989             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn)
1990             self.fail()
1991         except LdbError, (num, _):
1992             self.assertTrue(num in (ERR_UNWILLING_TO_PERFORM, ERR_OTHER))
1993
1994         print "Testing delete (should fail, not a leaf node) of renamed cn=ldaptestcontainer2," + self.base_dn
1995         try:
1996             ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
1997             self.fail()
1998         except LdbError, (num, _):
1999             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
2000
2001         print "Testing base ldb.search for CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn
2002         res = ldb.search(expression="(objectclass=*)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
2003         self.assertEquals(len(res), 1)
2004         res = ldb.search(expression="(cn=ldaptestuser40)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
2005         self.assertEquals(len(res), 0)
2006
2007         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
2008         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_ONELEVEL)
2009         # FIXME: self.assertEquals(len(res), 0)
2010
2011         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
2012         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_SUBTREE)
2013         # FIXME: self.assertEquals(len(res), 0)
2014
2015         print "Testing delete of subtree renamed "+("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn)
2016         ldb.delete(("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
2017         print "Testing delete of renamed cn=ldaptestcontainer2," + self.base_dn
2018         ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
2019
2020         ldb.add({"dn": "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
2021
2022         ldb.add({"dn": "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
2023
2024         print "Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))"
2025         res = ldb.search(expression="(&(cn=ldaptestuser)(objectClass=user))")
2026         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
2027
2028         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
2029         self.assertEquals(str(res[0]["cn"]), "ldaptestuser")
2030         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
2031         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user"]))
2032         self.assertTrue("objectGUID" in res[0])
2033         self.assertTrue("whenCreated" in res[0])
2034         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Person,CN=Schema,CN=Configuration," + self.base_dn))
2035         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
2036         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
2037         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2038         self.assertEquals(len(res[0]["memberOf"]), 1)
2039
2040         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))"
2041         res2 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))")
2042         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))")
2043
2044         self.assertEquals(res[0].dn, res2[0].dn)
2045
2046         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon))"
2047         res3 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
2048         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)): matched %d" % len(res3))
2049
2050         self.assertEquals(res[0].dn, res3[0].dn)
2051
2052         if gc_ldb is not None:
2053             print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog"
2054             res3gc = gc_ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
2055             self.assertEquals(len(res3gc), 1)
2056
2057             self.assertEquals(res[0].dn, res3gc[0].dn)
2058
2059         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in with 'phantom root' control"
2060
2061         if gc_ldb is not None:
2062             res3control = gc_ldb.search(self.base_dn, expression="(&(cn=ldaptestuser)(objectCategory=PerSon))", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
2063             self.assertEquals(len(res3control), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog")
2064
2065             self.assertEquals(res[0].dn, res3control[0].dn)
2066
2067         ldb.delete(res[0].dn)
2068
2069         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))"
2070         res = ldb.search(expression="(&(cn=ldaptestcomputer)(objectClass=user))")
2071         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
2072
2073         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer,CN=Computers," + self.base_dn))
2074         self.assertEquals(str(res[0]["cn"]), "ldaptestcomputer")
2075         self.assertEquals(str(res[0]["name"]), "ldaptestcomputer")
2076         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user", "computer"]))
2077         self.assertTrue("objectGUID" in res[0])
2078         self.assertTrue("whenCreated" in res[0])
2079         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn))
2080         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513)
2081         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
2082         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
2083         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2084         self.assertEquals(len(res[0]["memberOf"]), 1)
2085
2086         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))"
2087         res2 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
2088         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
2089
2090         self.assertEquals(res[0].dn, res2[0].dn)
2091
2092         if gc_ldb is not None:
2093             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog"
2094             res2gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
2095             self.assertEquals(len(res2gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog")
2096
2097             self.assertEquals(res[0].dn, res2gc[0].dn)
2098
2099         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER))"
2100         res3 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2101         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2102
2103         self.assertEquals(res[0].dn, res3[0].dn)
2104
2105         if gc_ldb is not None:
2106             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog"
2107             res3gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2108             self.assertEquals(len(res3gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog")
2109
2110             self.assertEquals(res[0].dn, res3gc[0].dn)
2111
2112         print "Testing ldb.search for (&(cn=ldaptestcomp*r)(objectCategory=compuTER))"
2113         res4 = ldb.search(expression="(&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
2114         self.assertEquals(len(res4), 1, "Could not find (&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
2115
2116         self.assertEquals(res[0].dn, res4[0].dn)
2117
2118         print "Testing ldb.search for (&(cn=ldaptestcomput*)(objectCategory=compuTER))"
2119         res5 = ldb.search(expression="(&(cn=ldaptestcomput*)(objectCategory=compuTER))")
2120         self.assertEquals(len(res5), 1, "Could not find (&(cn=ldaptestcomput*)(objectCategory=compuTER))")
2121
2122         self.assertEquals(res[0].dn, res5[0].dn)
2123
2124         print "Testing ldb.search for (&(cn=*daptestcomputer)(objectCategory=compuTER))"
2125         res6 = ldb.search(expression="(&(cn=*daptestcomputer)(objectCategory=compuTER))")
2126         self.assertEquals(len(res6), 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))")
2127
2128         self.assertEquals(res[0].dn, res6[0].dn)
2129
2130         ldb.delete("<GUID=" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + ">")
2131
2132         print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))"
2133         res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))")
2134         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptest2computer)(objectClass=user))")
2135
2136         self.assertEquals(str(res[0].dn), "CN=ldaptest2computer,CN=Computers," + self.base_dn)
2137         self.assertEquals(str(res[0]["cn"]), "ldaptest2computer")
2138         self.assertEquals(str(res[0]["name"]), "ldaptest2computer")
2139         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user", "computer"])
2140         self.assertTrue("objectGUID" in res[0])
2141         self.assertTrue("whenCreated" in res[0])
2142         self.assertEquals(res[0]["objectCategory"][0], "CN=Computer,CN=Schema,CN=Configuration," + self.base_dn)
2143         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST)
2144         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT)
2145
2146         ldb.delete("<SID=" + ldb.schema_format_value("objectSID", res[0]["objectSID"][0]) + ">")
2147
2148         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "memberOf", "allowedAttributes", "allowedAttributesEffective"]
2149         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
2150         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
2151         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
2152
2153         self.assertEquals(str(res_user[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2154         self.assertEquals(str(res_user[0]["cn"]), "ldaptestuser2")
2155         self.assertEquals(str(res_user[0]["name"]), "ldaptestuser2")
2156         self.assertEquals(list(res_user[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
2157         self.assertTrue("objectSid" in res_user[0])
2158         self.assertTrue("objectGUID" in res_user[0])
2159         self.assertTrue("whenCreated" in res_user[0])
2160         self.assertTrue("nTSecurityDescriptor" in res_user[0])
2161         self.assertTrue("allowedAttributes" in res_user[0])
2162         self.assertTrue("allowedAttributesEffective" in res_user[0])
2163         self.assertEquals(res_user[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2164
2165         ldaptestuser2_sid = res_user[0]["objectSid"][0]
2166         ldaptestuser2_guid = res_user[0]["objectGUID"][0]
2167
2168         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "member", "allowedAttributes", "allowedAttributesEffective"]
2169         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))"
2170         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2171         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2172
2173         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2174         self.assertEquals(str(res[0]["cn"]), "ldaptestgroup2")
2175         self.assertEquals(str(res[0]["name"]), "ldaptestgroup2")
2176         self.assertEquals(list(res[0]["objectClass"]), ["top", "group"])
2177         self.assertTrue("objectGUID" in res[0])
2178         self.assertTrue("objectSid" in res[0])
2179         self.assertTrue("whenCreated" in res[0])
2180         self.assertTrue("nTSecurityDescriptor" in res[0])
2181         self.assertTrue("allowedAttributes" in res[0])
2182         self.assertTrue("allowedAttributesEffective" in res[0])
2183         memberUP = []
2184         for m in res[0]["member"]:
2185             memberUP.append(m.upper())
2186         self.assertTrue(("CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
2187
2188         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs, controls=["extended_dn:1:1"])
2189         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2190
2191         print res[0]["member"]
2192         memberUP = []
2193         for m in res[0]["member"]:
2194             memberUP.append(m.upper())
2195         print ("<GUID=" + ldb.schema_format_value("objectGUID", ldaptestuser2_guid) + ">;<SID=" + ldb.schema_format_value("objectSid", ldaptestuser2_sid) + ">;CN=ldaptestuser2,CN=Users," + self.base_dn).upper()
2196
2197         self.assertTrue(("<GUID=" + ldb.schema_format_value("objectGUID", ldaptestuser2_guid) + ">;<SID=" + ldb.schema_format_value("objectSid", ldaptestuser2_sid) + ">;CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
2198
2199         print "Quicktest for linked attributes"
2200         ldb.modify_ldif("""
2201 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2202 changetype: modify
2203 replace: member
2204 member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
2205 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2206 """)
2207
2208         ldb.modify_ldif("""
2209 dn: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
2210 changetype: modify
2211 replace: member
2212 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2213 """)
2214
2215         ldb.modify_ldif("""
2216 dn: <SID=""" + ldb.schema_format_value("objectSid", res[0]["objectSid"][0]) + """>
2217 changetype: modify
2218 delete: member
2219 """)
2220
2221         ldb.modify_ldif("""
2222 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2223 changetype: modify
2224 add: member
2225 member: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
2226 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2227 """)
2228
2229         ldb.modify_ldif("""
2230 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2231 changetype: modify
2232 replace: member
2233 """)
2234
2235         ldb.modify_ldif("""
2236 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2237 changetype: modify
2238 add: member
2239 member: <SID=""" + ldb.schema_format_value("objectSid", res_user[0]["objectSid"][0]) + """>
2240 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2241 """)
2242
2243         ldb.modify_ldif("""
2244 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2245 changetype: modify
2246 delete: member
2247 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2248 """)
2249
2250         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2251         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2252
2253         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2254         self.assertEquals(res[0]["member"][0], ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2255         self.assertEquals(len(res[0]["member"]), 1)
2256
2257         ldb.delete(("CN=ldaptestuser2,CN=Users," + self.base_dn))
2258
2259         time.sleep(4)
2260
2261         attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]
2262         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
2263         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2264         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete")
2265
2266         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2267         self.assertTrue("member" not in res[0])
2268
2269         print "Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))"
2270 # TODO UTF8 users don't seem to work fully anymore
2271 #        res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2272         res = ldb.search(expression="(&(cn=ldaptestutf8user èùéìòà)(objectclass=user))")
2273         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2274
2275         self.assertEquals(str(res[0].dn), ("CN=ldaptestutf8user èùéìòà,CN=Users," + self.base_dn))
2276         self.assertEquals(str(res[0]["cn"]), "ldaptestutf8user èùéìòà")
2277         self.assertEquals(str(res[0]["name"]), "ldaptestutf8user èùéìòà")
2278         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
2279         self.assertTrue("objectGUID" in res[0])
2280         self.assertTrue("whenCreated" in res[0])
2281
2282         ldb.delete(res[0].dn)
2283
2284         print "Testing ldb.search for (&(cn=ldaptestutf8user2*)(objectClass=user))"
2285         res = ldb.search(expression="(&(cn=ldaptestutf8user2*)(objectClass=user))")
2286         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user2*)(objectClass=user))")
2287
2288         ldb.delete(res[0].dn)
2289
2290         ldb.delete(("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2291
2292         print "Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))"
2293 # TODO UTF8 users don't seem to work fully anymore
2294 #        res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2295 #        self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2296
2297         print "Testing that we can't get at the configuration DN from the main search base"
2298         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2299         self.assertEquals(len(res), 0)
2300
2301         print "Testing that we can get at the configuration DN from the main search base on the LDAP port with the 'phantom root' search_options control"
2302         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
2303         self.assertTrue(len(res) > 0)
2304
2305         if gc_ldb is not None:
2306             print "Testing that we can get at the configuration DN from the main search base on the GC port with the search_options control == 0"
2307
2308             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:0"])
2309             self.assertTrue(len(res) > 0)
2310
2311             print "Testing that we do find configuration elements in the global catlog"
2312             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2313             self.assertTrue(len(res) > 0)
2314
2315             print "Testing that we do find configuration elements and user elements at the same time"
2316             res = gc_ldb.search(self.base_dn, expression="(|(objectClass=crossRef)(objectClass=person))", scope=SCOPE_SUBTREE, attrs=["cn"])
2317             self.assertTrue(len(res) > 0)
2318
2319             print "Testing that we do find configuration elements in the global catlog, with the configuration basedn"
2320             res = gc_ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2321             self.assertTrue(len(res) > 0)
2322
2323         print "Testing that we can get at the configuration DN on the main LDAP port"
2324         res = ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2325         self.assertTrue(len(res) > 0)
2326
2327         print "Testing objectCategory canonacolisation"
2328         res = ldb.search(self.configuration_dn, expression="objectCategory=ntDsDSA", scope=SCOPE_SUBTREE, attrs=["cn"])
2329         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=ntDsDSA")
2330         self.assertTrue(len(res) != 0)
2331
2332         res = ldb.search(self.configuration_dn, expression="objectCategory=CN=ntDs-DSA," + self.schema_dn, scope=SCOPE_SUBTREE, attrs=["cn"])
2333         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=CN=ntDs-DSA," + self.schema_dn)
2334         self.assertTrue(len(res) != 0)
2335
2336         print "Testing objectClass attribute order on "+ self.base_dn
2337         res = ldb.search(expression="objectClass=domain", base=self.base_dn,
2338                          scope=SCOPE_BASE, attrs=["objectClass"])
2339         self.assertEquals(len(res), 1)
2340
2341         self.assertEquals(list(res[0]["objectClass"]), ["top", "domain", "domainDNS"])
2342
2343     #  check enumeration
2344
2345         print "Testing ldb.search for objectCategory=person"
2346         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"])
2347         self.assertTrue(len(res) > 0)
2348
2349         print "Testing ldb.search for objectCategory=person with domain scope control"
2350         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2351         self.assertTrue(len(res) > 0)
2352
2353         print "Testing ldb.search for objectCategory=user"
2354         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"])
2355         self.assertTrue(len(res) > 0)
2356
2357         print "Testing ldb.search for objectCategory=user with domain scope control"
2358         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2359         self.assertTrue(len(res) > 0)
2360
2361         print "Testing ldb.search for objectCategory=group"
2362         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"])
2363         self.assertTrue(len(res) > 0)
2364
2365         print "Testing ldb.search for objectCategory=group with domain scope control"
2366         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2367         self.assertTrue(len(res) > 0)
2368
2369         print "Testing creating a user with the posixAccount objectClass"
2370         self.ldb.add_ldif("""dn: cn=posixuser,CN=Users,%s
2371 objectClass: top
2372 objectClass: person
2373 objectClass: posixAccount
2374 objectClass: user
2375 objectClass: organizationalPerson
2376 cn: posixuser
2377 uid: posixuser
2378 sn: posixuser
2379 uidNumber: 10126
2380 gidNumber: 10126
2381 homeDirectory: /home/posixuser
2382 loginShell: /bin/bash
2383 gecos: Posix User;;;
2384 description: A POSIX user"""% (self.base_dn))
2385
2386         print "Testing removing the posixAccount objectClass from an existing user"
2387         self.ldb.modify_ldif("""dn: cn=posixuser,CN=Users,%s
2388 changetype: modify
2389 delete: objectClass
2390 objectClass: posixAccount"""% (self.base_dn))
2391
2392         print "Testing adding the posixAccount objectClass to an existing user"
2393         self.ldb.modify_ldif("""dn: cn=posixuser,CN=Users,%s
2394 changetype: modify
2395 add: objectClass
2396 objectClass: posixAccount"""% (self.base_dn))
2397
2398         self.delete_force(self.ldb, "cn=posixuser,cn=users," + self.base_dn)
2399         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2400         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2401         self.delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
2402         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
2403         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
2404         self.delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
2405         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2406         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
2407         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2408         self.delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
2409         self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
2410         self.delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
2411         self.delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
2412         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
2413         self.delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
2414
2415     def test_security_descriptor_add(self):
2416         """ Testing ldb.add_ldif() for nTSecurityDescriptor """
2417         user_name = "testdescriptoruser1"
2418         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2419         #
2420         # Test an empty security descriptor (naturally this shouldn't work)
2421         #
2422         self.delete_force(self.ldb, user_dn)
2423         try:
2424             self.ldb.add({ "dn": user_dn,
2425                            "objectClass": "user",
2426                            "sAMAccountName": user_name,
2427                            "nTSecurityDescriptor": [] })
2428             self.fail()
2429         except LdbError, (num, _):
2430             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2431         finally:
2432             self.delete_force(self.ldb, user_dn)
2433         #
2434         # Test add_ldif() with SDDL security descriptor input
2435         #
2436         try:
2437             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2438             self.ldb.add_ldif("""
2439 dn: """ + user_dn + """
2440 objectclass: user
2441 sAMAccountName: """ + user_name + """
2442 nTSecurityDescriptor: """ + sddl)
2443             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2444             desc = res[0]["nTSecurityDescriptor"][0]
2445             desc = ndr_unpack( security.descriptor, desc )
2446             desc_sddl = desc.as_sddl( self.domain_sid )
2447             self.assertEqual(desc_sddl, sddl)
2448         finally:
2449             self.delete_force(self.ldb, user_dn)
2450         #
2451         # Test add_ldif() with BASE64 security descriptor
2452         #
2453         try:
2454             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2455             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2456             desc_binary = ndr_pack(desc)
2457             desc_base64 = base64.b64encode(desc_binary)
2458             self.ldb.add_ldif("""
2459 dn: """ + user_dn + """
2460 objectclass: user
2461 sAMAccountName: """ + user_name + """
2462 nTSecurityDescriptor:: """ + desc_base64)
2463             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2464             desc = res[0]["nTSecurityDescriptor"][0]
2465             desc = ndr_unpack(security.descriptor, desc)
2466             desc_sddl = desc.as_sddl(self.domain_sid)
2467             self.assertEqual(desc_sddl, sddl)
2468         finally:
2469             self.delete_force(self.ldb, user_dn)
2470
2471     def test_security_descriptor_add_neg(self):
2472         """Test add_ldif() with BASE64 security descriptor input using WRONG domain SID
2473             Negative test
2474         """
2475         user_name = "testdescriptoruser1"
2476         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2477         self.delete_force(self.ldb, user_dn)
2478         try:
2479             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2480             desc = security.descriptor.from_sddl(sddl, security.dom_sid('S-1-5-21'))
2481             desc_base64 = base64.b64encode( ndr_pack(desc) )
2482             self.ldb.add_ldif("""
2483 dn: """ + user_dn + """
2484 objectclass: user
2485 sAMAccountName: """ + user_name + """
2486 nTSecurityDescriptor:: """ + desc_base64)
2487             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2488             self.assertTrue("nTSecurityDescriptor" in res[0])
2489         finally:
2490             self.delete_force(self.ldb, user_dn)
2491
2492     def test_security_descriptor_modify(self):
2493         """ Testing ldb.modify_ldif() for nTSecurityDescriptor """
2494         user_name = "testdescriptoruser2"
2495         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2496         #
2497         # Test an empty security descriptor (naturally this shouldn't work)
2498         #
2499         self.delete_force(self.ldb, user_dn)
2500         self.ldb.add({ "dn": user_dn,
2501                        "objectClass": "user",
2502                        "sAMAccountName": user_name })
2503
2504         m = Message()
2505         m.dn = Dn(ldb, user_dn)
2506         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_ADD,
2507                                                    "nTSecurityDescriptor")
2508         try:
2509             self.ldb.modify(m)
2510             self.fail()
2511         except LdbError, (num, _):
2512             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2513
2514         m = Message()
2515         m.dn = Dn(ldb, user_dn)
2516         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_REPLACE,
2517                                                    "nTSecurityDescriptor")
2518         try:
2519             self.ldb.modify(m)
2520             self.fail()
2521         except LdbError, (num, _):
2522             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2523
2524         m = Message()
2525         m.dn = Dn(ldb, user_dn)
2526         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_DELETE,
2527                                                    "nTSecurityDescriptor")
2528         try:
2529             self.ldb.modify(m)
2530             self.fail()
2531         except LdbError, (num, _):
2532             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2533
2534         self.delete_force(self.ldb, user_dn)
2535         #
2536         # Test modify_ldif() with SDDL security descriptor input
2537         # Add ACE to the original descriptor test
2538         #
2539         try:
2540             self.ldb.add_ldif("""
2541 dn: """ + user_dn + """
2542 objectclass: user
2543 sAMAccountName: """ + user_name)
2544             # Modify descriptor
2545             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2546             desc = res[0]["nTSecurityDescriptor"][0]
2547             desc = ndr_unpack(security.descriptor, desc)
2548             desc_sddl = desc.as_sddl(self.domain_sid)
2549             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
2550             mod = """
2551 dn: """ + user_dn + """
2552 changetype: modify
2553 replace: nTSecurityDescriptor
2554 nTSecurityDescriptor: """ + sddl
2555             self.ldb.modify_ldif(mod)
2556             # Read modified descriptor
2557             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2558             desc = res[0]["nTSecurityDescriptor"][0]
2559             desc = ndr_unpack(security.descriptor, desc)
2560             desc_sddl = desc.as_sddl(self.domain_sid)
2561             self.assertEqual(desc_sddl, sddl)
2562         finally:
2563             self.delete_force(self.ldb, user_dn)
2564         #
2565         # Test modify_ldif() with SDDL security descriptor input
2566         # New desctiptor test
2567         #
2568         try:
2569             self.ldb.add_ldif("""
2570 dn: """ + user_dn + """
2571 objectclass: user
2572 sAMAccountName: """ + user_name)
2573             # Modify descriptor
2574             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2575             mod = """
2576 dn: """ + user_dn + """
2577 changetype: modify
2578 replace: nTSecurityDescriptor
2579 nTSecurityDescriptor: """ + sddl
2580             self.ldb.modify_ldif(mod)
2581             # Read modified descriptor
2582             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2583             desc = res[0]["nTSecurityDescriptor"][0]
2584             desc = ndr_unpack(security.descriptor, desc)
2585             desc_sddl = desc.as_sddl(self.domain_sid)
2586             self.assertEqual(desc_sddl, sddl)
2587         finally:
2588             self.delete_force(self.ldb, user_dn)
2589         #
2590         # Test modify_ldif() with BASE64 security descriptor input
2591         # Add ACE to the original descriptor test
2592         #
2593         try:
2594             self.ldb.add_ldif("""
2595 dn: """ + user_dn + """
2596 objectclass: user
2597 sAMAccountName: """ + user_name)
2598             # Modify descriptor
2599             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2600             desc = res[0]["nTSecurityDescriptor"][0]
2601             desc = ndr_unpack(security.descriptor, desc)
2602             desc_sddl = desc.as_sddl(self.domain_sid)
2603             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
2604             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2605             desc_base64 = base64.b64encode(ndr_pack(desc))
2606             mod = """
2607 dn: """ + user_dn + """
2608 changetype: modify
2609 replace: nTSecurityDescriptor
2610 nTSecurityDescriptor:: """ + desc_base64
2611             self.ldb.modify_ldif(mod)
2612             # Read modified descriptor
2613             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2614             desc = res[0]["nTSecurityDescriptor"][0]
2615             desc = ndr_unpack(security.descriptor, desc)
2616             desc_sddl = desc.as_sddl(self.domain_sid)
2617             self.assertEqual(desc_sddl, sddl)
2618         finally:
2619             self.delete_force(self.ldb, user_dn)
2620         #
2621         # Test modify_ldif() with BASE64 security descriptor input
2622         # New descriptor test
2623         #
2624         try:
2625             self.delete_force(self.ldb, user_dn)
2626             self.ldb.add_ldif("""
2627 dn: """ + user_dn + """
2628 objectclass: user
2629 sAMAccountName: """ + user_name)
2630             # Modify descriptor
2631             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2632             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2633             desc_base64 = base64.b64encode(ndr_pack(desc))
2634             mod = """
2635 dn: """ + user_dn + """
2636 changetype: modify
2637 replace: nTSecurityDescriptor
2638 nTSecurityDescriptor:: """ + desc_base64
2639             self.ldb.modify_ldif(mod)
2640             # Read modified descriptor
2641             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2642             desc = res[0]["nTSecurityDescriptor"][0]
2643             desc = ndr_unpack(security.descriptor, desc)
2644             desc_sddl = desc.as_sddl(self.domain_sid)
2645             self.assertEqual(desc_sddl, sddl)
2646         finally:
2647             self.delete_force(self.ldb, user_dn)
2648
2649     def test_dsheuristics(self):
2650         """Tests the 'dSHeuristics' attribute"""
2651         print "Tests the 'dSHeuristics' attribute"""
2652
2653         # Get the current value to restore it later
2654         res = self.ldb.search("CN=Directory Service, CN=Windows NT, CN=Services, "
2655                               + self.configuration_dn, scope=SCOPE_BASE, attrs=["dSHeuristics"])
2656         if "dSHeuristics" in res[0]:
2657             dsheuristics = res[0]["dSHeuristics"][0]
2658         else:
2659             dsheuristics = None
2660         # Should not be longer than 18 chars?
2661         try:
2662             self.set_dsheuristics("123ABC-+!1asdfg@#^12")
2663         except LdbError, (num, _):
2664             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2665         # If it is >= 10 chars, tenthChar should be 1
2666         try:
2667             self.set_dsheuristics("00020000000002")
2668         except LdbError, (num, _):
2669             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2670         # apart from the above, all char values are accepted
2671         self.set_dsheuristics("123ABC-+!1asdfg@#^")
2672         res = self.ldb.search("CN=Directory Service, CN=Windows NT, CN=Services, "
2673                               + self.configuration_dn, scope=SCOPE_BASE, attrs=["dSHeuristics"])
2674         self.assertTrue("dSHeuristics" in res[0])
2675         self.assertEquals(res[0]["dSHeuristics"][0], "123ABC-+!1asdfg@#^")
2676         # restore old value
2677         self.set_dsheuristics(dsheuristics)
2678
2679
2680 class BaseDnTests(unittest.TestCase):
2681
2682     def setUp(self):
2683         super(BaseDnTests, self).setUp()
2684         self.ldb = ldb
2685
2686     def test_rootdse_attrs(self):
2687         """Testing for all rootDSE attributes"""
2688         res = self.ldb.search(scope=SCOPE_BASE, attrs=[])
2689         self.assertEquals(len(res), 1)
2690
2691     def test_highestcommittedusn(self):
2692         """Testing for highestCommittedUSN"""
2693         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["highestCommittedUSN"])
2694         self.assertEquals(len(res), 1)
2695         self.assertTrue(int(res[0]["highestCommittedUSN"][0]) != 0)
2696
2697     def test_netlogon(self):
2698         """Testing for netlogon via LDAP"""
2699         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["netlogon"])
2700         self.assertEquals(len(res), 0)
2701
2702     def test_netlogon_highestcommitted_usn(self):
2703         """Testing for netlogon and highestCommittedUSN via LDAP"""
2704         res = self.ldb.search("", scope=SCOPE_BASE,
2705                 attrs=["netlogon", "highestCommittedUSN"])
2706         self.assertEquals(len(res), 0)
2707
2708     def test_namingContexts(self):
2709         """Testing for namingContexts in rootDSE"""
2710         res = self.ldb.search("", scope=SCOPE_BASE,
2711                 attrs=["namingContexts", "defaultNamingContext", "schemaNamingContext", "configurationNamingContext"])
2712         self.assertEquals(len(res), 1)
2713
2714         ncs = set([])
2715         for nc in res[0]["namingContexts"]:
2716             self.assertTrue(nc not in ncs)
2717             ncs.add(nc)
2718
2719         self.assertTrue(res[0]["defaultNamingContext"][0] in ncs)
2720         self.assertTrue(res[0]["configurationNamingContext"][0] in ncs)
2721         self.assertTrue(res[0]["schemaNamingContext"][0] in ncs)
2722
2723     def test_serverPath(self):
2724         """Testing the server paths in rootDSE"""
2725         res = self.ldb.search("", scope=SCOPE_BASE,
2726                               attrs=["dsServiceName", "serverName"])
2727         self.assertEquals(len(res), 1)
2728
2729         self.assertTrue("CN=Servers" in res[0]["dsServiceName"][0])
2730         self.assertTrue("CN=Sites" in res[0]["dsServiceName"][0])
2731         self.assertTrue("CN=NTDS Settings" in res[0]["dsServiceName"][0])
2732         self.assertTrue("CN=Servers" in res[0]["serverName"][0])
2733         self.assertTrue("CN=Sites" in res[0]["serverName"][0])
2734         self.assertFalse("CN=NTDS Settings" in res[0]["serverName"][0])
2735
2736     def test_dnsHostname(self):
2737         """Testing the DNS hostname in rootDSE"""
2738         res = self.ldb.search("", scope=SCOPE_BASE,
2739                               attrs=["dnsHostName", "serverName"])
2740         self.assertEquals(len(res), 1)
2741
2742         res2 = self.ldb.search(res[0]["serverName"][0], scope=SCOPE_BASE,
2743                                attrs=["dNSHostName"])
2744         self.assertEquals(len(res2), 1)
2745
2746         self.assertEquals(res[0]["dnsHostName"][0], res2[0]["dNSHostName"][0])
2747
2748     def test_ldapServiceName(self):
2749         """Testing the ldap service name in rootDSE"""
2750         res = self.ldb.search("", scope=SCOPE_BASE,
2751                               attrs=["ldapServiceName", "dNSHostName"])
2752         self.assertEquals(len(res), 1)
2753
2754         (hostname, _, dns_domainname) = res[0]["dNSHostName"][0].partition(".")
2755         self.assertTrue(":%s$@%s" % (hostname, dns_domainname.upper())
2756                         in res[0]["ldapServiceName"][0])
2757
2758 if not "://" in host:
2759     if os.path.isfile(host):
2760         host = "tdb://%s" % host
2761     else:
2762         host = "ldap://%s" % host
2763
2764 ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
2765 if not "tdb://" in host:
2766     gc_ldb = Ldb("%s:3268" % host, credentials=creds,
2767                  session_info=system_session(), lp=lp)
2768 else:
2769     gc_ldb = None
2770
2771 runner = SubunitTestRunner()
2772 rc = 0
2773 if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful():
2774     rc = 1
2775 if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful():
2776     rc = 1
2777 sys.exit(rc)