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