fe17a0a8d1303644914b7f152a728dd6b0b95660
[metze/samba/wip.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         # "appliesTo is defined with rangeLower: 36 and rangeUpper: 36
738         # and it's not allowed on objectClass: person
739         try:
740             ldb.add({
741                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
742                "objectClass": "person",
743                "appliesTo": "" })
744             self.fail()
745         except LdbError, (num, _):
746             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
747
748         try:
749             ldb.add({
750                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
751                "objectClass": "person",
752                "appliesTo": "a" })
753             self.fail()
754         except LdbError, (num, _):
755             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
756
757         try:
758             ldb.add({
759                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
760                "objectClass": "person",
761                "appliesTo": "01234567890123456789012345678901345" })
762             self.fail()
763         except LdbError, (num, _):
764             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
765
766         try:
767             ldb.add({
768                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
769                "objectClass": "person",
770                "appliesTo": "012345678901234567890123456789013456" })
771             self.fail()
772         except LdbError, (num, _):
773             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
774
775         try:
776             ldb.add({
777                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
778                "objectClass": "person",
779                "appliesTo": "0123456789012345678901234567890134567" })
780             self.fail()
781         except LdbError, (num, _):
782             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
783
784         ldb.add({
785            "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
786            "objectClass": "person" })
787
788         # Too short (min. 1)
789         m = Message()
790         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
791         m["sn"] = MessageElement("", FLAG_MOD_REPLACE, "sn")
792         try:
793             ldb.modify(m)
794             self.fail()
795         except LdbError, (num, _):
796             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
797
798         # Too long (max. 64)
799         m = Message()
800         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
801         m["sn"] = MessageElement("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", FLAG_MOD_REPLACE, "sn")
802         try:
803             ldb.modify(m)
804             self.fail()
805         except LdbError, (num, _):
806             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
807
808         m = Message()
809         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
810         m["appliesTo"] = MessageElement("",
811                                         FLAG_MOD_ADD, "appliesTo")
812         try:
813             ldb.modify(m)
814             self.fail()
815         except LdbError, (num, _):
816             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
817
818         m = Message()
819         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
820         m["appliesTo"] = MessageElement("",
821                                         FLAG_MOD_REPLACE, "appliesTo")
822         try:
823             ldb.modify(m)
824             self.fail()
825         except LdbError, (num, _):
826             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
827
828         m = Message()
829         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
830         m["appliesTo"] = MessageElement("",
831                                         FLAG_MOD_ADD, "appliesTo")
832         try:
833             ldb.modify(m)
834             self.fail()
835         except LdbError, (num, _):
836             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
837
838         m = Message()
839         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
840         m["appliesTo"] = MessageElement("a",
841                                         FLAG_MOD_REPLACE, "appliesTo")
842         try:
843             ldb.modify(m)
844             self.fail()
845         except LdbError, (num, _):
846             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
847
848         m = Message()
849         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
850         m["appliesTo"] = MessageElement("01234567890123456789012345678901345",
851                                         FLAG_MOD_ADD, "appliesTo")
852         try:
853             ldb.modify(m)
854             self.fail()
855         except LdbError, (num, _):
856             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
857
858         m = Message()
859         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
860         m["appliesTo"] = MessageElement("01234567890123456789012345678901345",
861                                         FLAG_MOD_REPLACE, "appliesTo")
862         try:
863             ldb.modify(m)
864             self.fail()
865         except LdbError, (num, _):
866             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
867
868         m = Message()
869         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
870         m["appliesTo"] = MessageElement("012345678901234567890123456789013456",
871                                         FLAG_MOD_ADD, "appliesTo")
872         try:
873             ldb.modify(m)
874             self.fail()
875         except LdbError, (num, _):
876             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
877
878         m = Message()
879         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
880         m["appliesTo"] = MessageElement("012345678901234567890123456789013456",
881                                         FLAG_MOD_REPLACE, "appliesTo")
882         try:
883             ldb.modify(m)
884             self.fail()
885         except LdbError, (num, _):
886             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
887
888         m = Message()
889         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
890         m["appliesTo"] = MessageElement("0123456789012345678901234567890134567",
891                                         FLAG_MOD_ADD, "appliesTo")
892         try:
893             ldb.modify(m)
894             self.fail()
895         except LdbError, (num, _):
896             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
897
898         m = Message()
899         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
900         m["appliesTo"] = MessageElement("0123456789012345678901234567890134567",
901                                         FLAG_MOD_REPLACE, "appliesTo")
902         try:
903             ldb.modify(m)
904             self.fail()
905         except LdbError, (num, _):
906             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
907
908         m = Message()
909         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
910         m["sn"] = MessageElement("x", FLAG_MOD_REPLACE, "sn")
911         ldb.modify(m)
912
913         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
914
915     def test_empty_messages(self):
916         """Test empty messages"""
917         print "Test empty messages"""
918
919         m = Message()
920         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
921
922         try:
923             ldb.add(m)
924             self.fail()
925         except LdbError, (num, _):
926             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
927
928         try:
929             ldb.modify(m)
930             self.fail()
931         except LdbError, (num, _):
932             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
933
934         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
935
936     def test_empty_attributes(self):
937         """Test empty attributes"""
938         print "Test empty attributes"""
939
940         m = Message()
941         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
942         m["objectClass"] = MessageElement("group", FLAG_MOD_ADD, "objectClass")
943         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
944
945         try:
946             ldb.add(m)
947             self.fail()
948         except LdbError, (num, _):
949             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
950
951         self.ldb.add({
952             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
953             "objectclass": "group"})
954
955         m = Message()
956         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
957         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
958
959         try:
960             ldb.modify(m)
961             self.fail()
962         except LdbError, (num, _):
963             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
964
965         m = Message()
966         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
967         m["description"] = MessageElement([], FLAG_MOD_REPLACE, "description")
968         ldb.modify(m)
969
970         m = Message()
971         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
972         m["description"] = MessageElement([], FLAG_MOD_DELETE, "description")
973         try:
974             ldb.modify(m)
975             self.fail()
976         except LdbError, (num, _):
977             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
978
979         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
980
981     def test_instanceType(self):
982         """Tests the 'instanceType' attribute"""
983         print "Tests the 'instanceType' attribute"
984
985         # The instance type is single-valued
986         try:
987             self.ldb.add({
988                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
989                 "objectclass": "group",
990                 "instanceType": ["0", "1"]})
991             self.fail()
992         except LdbError, (num, _):
993             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
994
995         # The head NC flag cannot be set without the write flag
996         try:
997             self.ldb.add({
998                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
999                 "objectclass": "group",
1000                 "instanceType": "1" })
1001             self.fail()
1002         except LdbError, (num, _):
1003             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1004
1005         # We cannot manipulate NCs without the head NC flag
1006         try:
1007             self.ldb.add({
1008                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1009                 "objectclass": "group",
1010                 "instanceType": "32" })
1011             self.fail()
1012         except LdbError, (num, _):
1013             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1014
1015         self.ldb.add({
1016              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1017              "objectclass": "group"})
1018
1019         m = Message()
1020         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1021         m["instanceType"] = MessageElement("0", FLAG_MOD_REPLACE,
1022           "instanceType")
1023         try:
1024             ldb.modify(m)
1025             self.fail()
1026         except LdbError, (num, _):
1027             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1028
1029         m = Message()
1030         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1031         m["instanceType"] = MessageElement([], FLAG_MOD_REPLACE,
1032           "instanceType")
1033         try:
1034             ldb.modify(m)
1035             self.fail()
1036         except LdbError, (num, _):
1037             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1038
1039         m = Message()
1040         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1041         m["instanceType"] = MessageElement([], FLAG_MOD_DELETE, "instanceType")
1042         try:
1043             ldb.modify(m)
1044             self.fail()
1045         except LdbError, (num, _):
1046             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1047
1048         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1049
1050     def test_distinguished_name(self):
1051         """Tests the 'distinguishedName' attribute"""
1052         print "Tests the 'distinguishedName' attribute"
1053
1054         # The "dn" shortcut isn't supported
1055         m = Message()
1056         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1057         m["objectClass"] = MessageElement("group", 0, "objectClass")
1058         m["dn"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn, 0,
1059           "dn")
1060         try:
1061             ldb.add(m)
1062             self.fail()
1063         except LdbError, (num, _):
1064             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
1065
1066         # a wrong "distinguishedName" attribute is obviously tolerated
1067         self.ldb.add({
1068               "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1069               "objectclass": "group",
1070               "distinguishedName": "cn=ldaptest,cn=users," + self.base_dn})
1071
1072         # proof if the DN has been set correctly
1073         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1074                          scope=SCOPE_BASE, attrs=["distinguishedName"])
1075         self.assertTrue(len(res) == 1)
1076         self.assertTrue("distinguishedName" in res[0])
1077         self.assertTrue(Dn(ldb, res[0]["distinguishedName"][0])
1078            == Dn(ldb, "cn=ldaptestgroup, cn=users," + self.base_dn))
1079
1080         # The "dn" shortcut isn't supported
1081         m = Message()
1082         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1083         m["dn"] = MessageElement(
1084           "cn=ldaptestgroup,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
1085           "dn")
1086         try:
1087             ldb.modify(m)
1088             self.fail()
1089         except LdbError, (num, _):
1090             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
1091
1092         m = Message()
1093         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1094         m["distinguishedName"] = MessageElement(
1095           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_ADD,
1096           "distinguishedName")
1097
1098         try:
1099             ldb.modify(m)
1100             self.fail()
1101         except LdbError, (num, _):
1102             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1103
1104         m = Message()
1105         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1106         m["distinguishedName"] = MessageElement(
1107           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
1108           "distinguishedName")
1109
1110         try:
1111             ldb.modify(m)
1112             self.fail()
1113         except LdbError, (num, _):
1114             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1115
1116         m = Message()
1117         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1118         m["distinguishedName"] = MessageElement(
1119           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_DELETE,
1120           "distinguishedName")
1121
1122         try:
1123             ldb.modify(m)
1124             self.fail()
1125         except LdbError, (num, _):
1126             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1127
1128         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1129
1130     def test_rdn_name(self):
1131         """Tests the RDN"""
1132         print "Tests the RDN"
1133
1134         # Search
1135
1136         # empty RDN
1137         try:
1138             self.ldb.search("=,cn=users," + self.base_dn, scope=SCOPE_BASE)
1139             self.fail()
1140         except LdbError, (num, _):
1141             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1142
1143         # empty RDN name
1144         try:
1145             self.ldb.search("cn=,cn=users," + self.base_dn, scope=SCOPE_BASE)
1146             self.fail()
1147         except LdbError, (num, _):
1148             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1149
1150         try:
1151             self.ldb.search("=ldaptestgroup,cn=users," + self.base_dn, scope=SCOPE_BASE)
1152             self.fail()
1153         except LdbError, (num, _):
1154             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1155
1156         # Add
1157
1158         # empty RDN
1159         try:
1160             self.ldb.add({
1161                  "dn": "=,cn=users," + self.base_dn,
1162                  "objectclass": "group"})
1163             self.fail()
1164         except LdbError, (num, _):
1165             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1166
1167         # empty RDN name
1168         try:
1169             self.ldb.add({
1170                  "dn": "=ldaptestgroup,cn=users," + self.base_dn,
1171                  "objectclass": "group"})
1172             self.fail()
1173         except LdbError, (num, _):
1174             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1175
1176         # empty RDN value
1177         try:
1178             self.ldb.add({
1179                  "dn": "cn=,cn=users," + self.base_dn,
1180                  "objectclass": "group"})
1181             self.fail()
1182         except LdbError, (num, _):
1183             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1184
1185         # a wrong RDN candidate
1186         try:
1187             self.ldb.add({
1188                  "dn": "description=xyz,cn=users," + self.base_dn,
1189                  "objectclass": "group"})
1190             self.fail()
1191         except LdbError, (num, _):
1192             self.assertEquals(num, ERR_NAMING_VIOLATION)
1193
1194         delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
1195
1196         # a wrong "name" attribute is obviously tolerated
1197         self.ldb.add({
1198              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1199              "objectclass": "group",
1200              "name": "ldaptestgroupx"})
1201
1202         # proof if the name has been set correctly
1203         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1204                          scope=SCOPE_BASE, attrs=["name"])
1205         self.assertTrue(len(res) == 1)
1206         self.assertTrue("name" in res[0])
1207         self.assertTrue(res[0]["name"][0] == "ldaptestgroup")
1208
1209         # Modify
1210
1211         # empty RDN value
1212         m = Message()
1213         m.dn = Dn(ldb, "cn=,cn=users," + self.base_dn)
1214         m["description"] = "test"
1215         try:
1216             self.ldb.modify(m)
1217             self.fail()
1218         except LdbError, (num, _):
1219             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1220
1221         # Delete
1222
1223         # empty RDN value
1224         try:
1225             self.ldb.delete("cn=,cn=users," + self.base_dn)
1226             self.fail()
1227         except LdbError, (num, _):
1228             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1229
1230         # Rename
1231
1232         # new empty RDN
1233         try:
1234             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
1235                             "=,cn=users," + self.base_dn)
1236             self.fail()
1237         except LdbError, (num, _):
1238             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1239
1240         # new empty RDN name
1241         try:
1242             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
1243                             "=ldaptestgroup,cn=users," + self.base_dn)
1244             self.fail()
1245         except LdbError, (num, _):
1246             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1247
1248         # new empty RDN value
1249         try:
1250             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
1251                             "cn=,cn=users," + self.base_dn)
1252             self.fail()
1253         except LdbError, (num, _):
1254             self.assertEquals(num, ERR_NAMING_VIOLATION)
1255
1256         # new wrong RDN candidate
1257         try:
1258             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
1259                             "description=xyz,cn=users," + self.base_dn)
1260             self.fail()
1261         except LdbError, (num, _):
1262             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1263
1264         delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
1265
1266         # old empty RDN value
1267         try:
1268             self.ldb.rename("cn=,cn=users," + self.base_dn,
1269                             "cn=ldaptestgroup,cn=users," + self.base_dn)
1270             self.fail()
1271         except LdbError, (num, _):
1272             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1273
1274         # names
1275
1276         m = Message()
1277         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1278         m["name"] = MessageElement("cn=ldaptestuser", FLAG_MOD_REPLACE,
1279           "name")
1280         try:
1281             ldb.modify(m)
1282             self.fail()
1283         except LdbError, (num, _):
1284             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
1285
1286         m = Message()
1287         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1288         m["cn"] = MessageElement("ldaptestuser",
1289           FLAG_MOD_REPLACE, "cn")
1290         try:
1291             ldb.modify(m)
1292             self.fail()
1293         except LdbError, (num, _):
1294             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
1295
1296         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1297
1298
1299         # this test needs to be disabled until we really understand
1300         # what the rDN length constraints are
1301     def DISABLED_test_largeRDN(self):
1302         """Testing large rDN (limit 64 characters)"""
1303         rdn = "CN=a012345678901234567890123456789012345678901234567890123456789012";
1304         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1305         ldif = """
1306 dn: %s,%s""" % (rdn,self.base_dn) + """
1307 objectClass: container
1308 """
1309         self.ldb.add_ldif(ldif)
1310         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1311
1312         rdn = "CN=a0123456789012345678901234567890123456789012345678901234567890120";
1313         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1314         try:
1315             ldif = """
1316 dn: %s,%s""" % (rdn,self.base_dn) + """
1317 objectClass: container
1318 """
1319             self.ldb.add_ldif(ldif)
1320             self.fail()
1321         except LdbError, (num, _):
1322             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1323         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1324
1325     def test_rename(self):
1326         """Tests the rename operation"""
1327         print "Tests the rename operations"
1328
1329         try:
1330             # cannot rename to be a child of itself
1331             ldb.rename(self.base_dn, "dc=test," + self.base_dn)
1332             self.fail()
1333         except LdbError, (num, _):
1334             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1335
1336         try:
1337             # inexistent object
1338             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1339             self.fail()
1340         except LdbError, (num, _):
1341             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1342
1343         self.ldb.add({
1344              "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
1345              "objectclass": "user" })
1346
1347         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1348         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
1349         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestUSER3,cn=users," + self.base_dn)
1350
1351         try:
1352             # containment problem: a user entry cannot contain user entries
1353             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser4,cn=ldaptestuser3,cn=users," + self.base_dn)
1354             self.fail()
1355         except LdbError, (num, _):
1356             self.assertEquals(num, ERR_NAMING_VIOLATION)
1357
1358         try:
1359             # invalid parent
1360             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=people,cn=users," + self.base_dn)
1361             self.fail()
1362         except LdbError, (num, _):
1363             self.assertEquals(num, ERR_OTHER)
1364
1365         try:
1366             # invalid target DN syntax
1367             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, ",cn=users," + self.base_dn)
1368             self.fail()
1369         except LdbError, (num, _):
1370             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1371
1372         try:
1373             # invalid RDN name
1374             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "ou=ldaptestuser3,cn=users," + self.base_dn)
1375             self.fail()
1376         except LdbError, (num, _):
1377             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1378
1379         delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
1380
1381         # Performs some "systemFlags" testing
1382
1383         # Move failing since no "SYSTEM_FLAG_CONFIG_ALLOW_MOVE"
1384         try:
1385             ldb.rename("CN=DisplaySpecifiers," + self.configuration_dn, "CN=DisplaySpecifiers,CN=Services," + self.configuration_dn)
1386             self.fail()
1387         except LdbError, (num, _):
1388             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1389
1390         # Limited move failing since no "SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE"
1391         try:
1392             ldb.rename("CN=Directory Service,CN=Windows NT,CN=Services," + self.configuration_dn, "CN=Directory Service,CN=RRAS,CN=Services," + self.configuration_dn)
1393             self.fail()
1394         except LdbError, (num, _):
1395             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1396
1397         # Rename failing since no "SYSTEM_FLAG_CONFIG_ALLOW_RENAME"
1398         try:
1399             ldb.rename("CN=DisplaySpecifiers," + self.configuration_dn, "CN=DisplaySpecifiers2," + self.configuration_dn)
1400             self.fail()
1401         except LdbError, (num, _):
1402             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1403
1404         # It's not really possible to test moves on the schema partition since
1405         # there don't exist subcontainers on it.
1406
1407         # Rename failing since "SYSTEM_FLAG_SCHEMA_BASE_OBJECT"
1408         try:
1409             ldb.rename("CN=Top," + self.schema_dn, "CN=Top2," + self.schema_dn)
1410             self.fail()
1411         except LdbError, (num, _):
1412             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1413
1414         # Move failing since "SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE"
1415         try:
1416             ldb.rename("CN=Users," + self.base_dn, "CN=Users,CN=Computers," + self.base_dn)
1417             self.fail()
1418         except LdbError, (num, _):
1419             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1420
1421         # Rename failing since "SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME"
1422         try:
1423             ldb.rename("CN=Users," + self.base_dn, "CN=Users2," + self.base_dn)
1424             self.fail()
1425         except LdbError, (num, _):
1426             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1427
1428         # Performs some other constraints testing
1429
1430         try:
1431             ldb.rename("CN=Policies,CN=System," + self.base_dn, "CN=Users2," + self.base_dn)
1432             self.fail()
1433         except LdbError, (num, _):
1434             self.assertEquals(num, ERR_OTHER)
1435
1436     def test_rename_twice(self):
1437         """Tests the rename operation twice - this corresponds to a past bug"""
1438         print "Tests the rename twice operation"
1439
1440         self.ldb.add({
1441              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
1442              "objectclass": "user" })
1443
1444         ldb.rename("cn=ldaptestuser5,cn=users," + self.base_dn, "cn=ldaptestUSER5,cn=users," + self.base_dn)
1445         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
1446         self.ldb.add({
1447              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
1448              "objectclass": "user" })
1449         ldb.rename("cn=ldaptestuser5,cn=Users," + self.base_dn, "cn=ldaptestUSER5,cn=users," + self.base_dn)
1450         res = ldb.search(expression="cn=ldaptestuser5")
1451         print "Found %u records" % len(res)
1452         self.assertEquals(len(res), 1, "Wrong number of hits for cn=ldaptestuser5")
1453         res = ldb.search(expression="(&(cn=ldaptestuser5)(objectclass=user))")
1454         print "Found %u records" % len(res)
1455         self.assertEquals(len(res), 1, "Wrong number of hits for (&(cn=ldaptestuser5)(objectclass=user))")
1456         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
1457
1458     def test_objectGUID(self):
1459         """Test objectGUID behaviour"""
1460         print "Testing objectGUID behaviour\n"
1461
1462         # The objectGUID cannot directly be set
1463         try:
1464             self.ldb.add_ldif("""
1465 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1466 objectClass: container
1467 objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
1468 """)
1469             self.fail()
1470         except LdbError, (num, _):
1471             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1472
1473         self.ldb.add({
1474             "dn": "cn=ldaptestcontainer," + self.base_dn,
1475             "objectClass": "container" })
1476
1477         # The objectGUID cannot directly be changed
1478         try:
1479             self.ldb.modify_ldif("""
1480 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1481 changetype: modify
1482 replace: objectGUID
1483 objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
1484 """)
1485             self.fail()
1486         except LdbError, (num, _):
1487             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1488
1489         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1490
1491     def test_parentGUID(self):
1492         """Test parentGUID behaviour"""
1493         print "Testing parentGUID behaviour\n"
1494
1495         self.ldb.add({
1496             "dn": "cn=parentguidtest,cn=users," + self.base_dn,
1497             "objectclass":"user",
1498             "samaccountname":"parentguidtest"});
1499         res1 = ldb.search(base="cn=parentguidtest,cn=users," + self.base_dn, scope=SCOPE_BASE,
1500                           attrs=["parentGUID", "samaccountname"]);
1501         res2 = ldb.search(base="cn=users," + self.base_dn,scope=SCOPE_BASE,
1502                           attrs=["objectGUID"]);
1503         res3 = ldb.search(base=self.base_dn, scope=SCOPE_BASE,
1504                           attrs=["parentGUID"]);
1505         res4 = ldb.search(base=self.configuration_dn, scope=SCOPE_BASE,
1506                           attrs=["parentGUID"]);
1507         res5 = ldb.search(base=self.schema_dn, scope=SCOPE_BASE,
1508                           attrs=["parentGUID"]);
1509
1510         """Check if the parentGUID is valid """
1511         self.assertEquals(res1[0]["parentGUID"], res2[0]["objectGUID"]);
1512
1513         """Check if it returns nothing when there is no parent object - default NC"""
1514         has_parentGUID = False
1515         for key in res3[0].keys():
1516             if key == "parentGUID":
1517                 has_parentGUID = True
1518                 break
1519         self.assertFalse(has_parentGUID);
1520
1521         """Check if it returns nothing when there is no parent object - configuration NC"""
1522         has_parentGUID = False
1523         for key in res4[0].keys():
1524             if key == "parentGUID":
1525                 has_parentGUID = True
1526                 break
1527         self.assertFalse(has_parentGUID);
1528
1529         """Check if it returns nothing when there is no parent object - schema NC"""
1530         has_parentGUID = False
1531         for key in res5[0].keys():
1532             if key == "parentGUID":
1533                 has_parentGUID = True
1534                 break
1535         self.assertFalse(has_parentGUID);
1536
1537         """Ensures that if you look for another object attribute after the constructed
1538             parentGUID, it will return correctly"""
1539         has_another_attribute = False
1540         for key in res1[0].keys():
1541             if key == "sAMAccountName":
1542                 has_another_attribute = True
1543                 break
1544         self.assertTrue(has_another_attribute)
1545         self.assertTrue(len(res1[0]["samaccountname"]) == 1)
1546         self.assertEquals(res1[0]["samaccountname"][0], "parentguidtest");
1547
1548         print "Testing parentGUID behaviour on rename\n"
1549
1550         self.ldb.add({
1551             "dn": "cn=testotherusers," + self.base_dn,
1552             "objectclass":"container"});
1553         res1 = ldb.search(base="cn=testotherusers," + self.base_dn,scope=SCOPE_BASE,
1554                           attrs=["objectGUID"]);
1555         ldb.rename("cn=parentguidtest,cn=users," + self.base_dn,
1556                    "cn=parentguidtest,cn=testotherusers," + self.base_dn);
1557         res2 = ldb.search(base="cn=parentguidtest,cn=testotherusers," + self.base_dn,
1558                           scope=SCOPE_BASE,
1559                           attrs=["parentGUID"]);
1560         self.assertEquals(res1[0]["objectGUID"], res2[0]["parentGUID"]);
1561
1562         delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
1563         delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
1564
1565     def test_usnChanged(self):
1566         """Test usnChanged behaviour"""
1567         print "Testing usnChanged behaviour\n"
1568
1569         self.ldb.add({
1570             "dn": "cn=ldaptestcontainer," + self.base_dn,
1571             "objectClass": "container" })
1572
1573         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1574                          scope=SCOPE_BASE,
1575                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged", "description"])
1576         self.assertTrue(len(res) == 1)
1577         self.assertFalse("description" in res[0])
1578         self.assertTrue("objectGUID" in res[0])
1579         self.assertTrue("uSNCreated" in res[0])
1580         self.assertTrue("uSNChanged" in res[0])
1581         self.assertTrue("whenCreated" in res[0])
1582         self.assertTrue("whenChanged" in res[0])
1583
1584         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1585
1586         # All this attributes are specificable on add operations
1587         self.ldb.add({
1588             "dn": "cn=ldaptestcontainer," + self.base_dn,
1589             "objectclass": "container",
1590             "uSNCreated" : "1",
1591             "uSNChanged" : "1",
1592             "whenCreated": timestring(long(time.time())),
1593             "whenChanged": timestring(long(time.time())) })
1594
1595         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1596                          scope=SCOPE_BASE,
1597                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged", "description"])
1598         self.assertTrue(len(res) == 1)
1599         self.assertFalse("description" in res[0])
1600         self.assertTrue("objectGUID" in res[0])
1601         self.assertTrue("uSNCreated" in res[0])
1602         self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
1603         self.assertTrue("uSNChanged" in res[0])
1604         self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
1605         self.assertTrue("whenCreated" in res[0])
1606         self.assertTrue("whenChanged" in res[0])
1607
1608         ldb.modify_ldif("""
1609 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1610 changetype: modify
1611 replace: description
1612 """)
1613
1614         res2 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1615                          scope=SCOPE_BASE,
1616                          attrs=["uSNCreated", "uSNChanged", "description"])
1617         self.assertTrue(len(res) == 1)
1618         self.assertFalse("description" in res2[0])
1619         self.assertEqual(res[0]["usnCreated"], res2[0]["usnCreated"])
1620         self.assertEqual(res[0]["usnCreated"], res2[0]["usnChanged"])
1621         self.assertEqual(res[0]["usnChanged"], res2[0]["usnChanged"])
1622
1623         ldb.modify_ldif("""
1624 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1625 changetype: modify
1626 replace: description
1627 description: test
1628 """)
1629
1630         res3 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1631                          scope=SCOPE_BASE,
1632                          attrs=["uSNCreated", "uSNChanged", "description"])
1633         self.assertTrue(len(res) == 1)
1634         self.assertTrue("description" in res3[0])
1635         self.assertEqual("test", str(res3[0]["description"][0]))
1636         self.assertEqual(res[0]["usnCreated"], res3[0]["usnCreated"])
1637         self.assertNotEqual(res[0]["usnCreated"], res3[0]["usnChanged"])
1638         self.assertNotEqual(res[0]["usnChanged"], res3[0]["usnChanged"])
1639
1640         ldb.modify_ldif("""
1641 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1642 changetype: modify
1643 replace: description
1644 description: test
1645 """)
1646
1647         res4 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1648                          scope=SCOPE_BASE,
1649                          attrs=["uSNCreated", "uSNChanged", "description"])
1650         self.assertTrue(len(res) == 1)
1651         self.assertTrue("description" in res4[0])
1652         self.assertEqual("test", str(res4[0]["description"][0]))
1653         self.assertEqual(res[0]["usnCreated"], res4[0]["usnCreated"])
1654         self.assertNotEqual(res3[0]["usnCreated"], res4[0]["usnChanged"])
1655         self.assertEqual(res3[0]["usnChanged"], res4[0]["usnChanged"])
1656
1657         ldb.modify_ldif("""
1658 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1659 changetype: modify
1660 replace: description
1661 description: test2
1662 """)
1663
1664         res5 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1665                          scope=SCOPE_BASE,
1666                          attrs=["uSNCreated", "uSNChanged", "description"])
1667         self.assertTrue(len(res) == 1)
1668         self.assertTrue("description" in res5[0])
1669         self.assertEqual("test2", str(res5[0]["description"][0]))
1670         self.assertEqual(res[0]["usnCreated"], res5[0]["usnCreated"])
1671         self.assertNotEqual(res3[0]["usnChanged"], res5[0]["usnChanged"])
1672
1673         ldb.modify_ldif("""
1674 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1675 changetype: modify
1676 delete: description
1677 description: test2
1678 """)
1679
1680         res6 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1681                          scope=SCOPE_BASE,
1682                          attrs=["uSNCreated", "uSNChanged", "description"])
1683         self.assertTrue(len(res) == 1)
1684         self.assertFalse("description" in res6[0])
1685         self.assertEqual(res[0]["usnCreated"], res6[0]["usnCreated"])
1686         self.assertNotEqual(res5[0]["usnChanged"], res6[0]["usnChanged"])
1687
1688         ldb.modify_ldif("""
1689 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1690 changetype: modify
1691 add: description
1692 description: test3
1693 """)
1694
1695         res7 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1696                          scope=SCOPE_BASE,
1697                          attrs=["uSNCreated", "uSNChanged", "description"])
1698         self.assertTrue(len(res) == 1)
1699         self.assertTrue("description" in res7[0])
1700         self.assertEqual("test3", str(res7[0]["description"][0]))
1701         self.assertEqual(res[0]["usnCreated"], res7[0]["usnCreated"])
1702         self.assertNotEqual(res6[0]["usnChanged"], res7[0]["usnChanged"])
1703
1704         ldb.modify_ldif("""
1705 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1706 changetype: modify
1707 delete: description
1708 """)
1709
1710         res8 = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1711                          scope=SCOPE_BASE,
1712                          attrs=["uSNCreated", "uSNChanged", "description"])
1713         self.assertTrue(len(res) == 1)
1714         self.assertFalse("description" in res8[0])
1715         self.assertEqual(res[0]["usnCreated"], res8[0]["usnCreated"])
1716         self.assertNotEqual(res7[0]["usnChanged"], res8[0]["usnChanged"])
1717
1718         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1719
1720     def test_groupType_int32(self):
1721         """Test groupType (int32) behaviour (should appear to be casted to a 32 bit signed integer before comparsion)"""
1722         print "Testing groupType (int32) behaviour\n"
1723
1724         res1 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
1725                           attrs=["groupType"], expression="groupType=2147483653");
1726
1727         res2 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
1728                           attrs=["groupType"], expression="groupType=-2147483643");
1729
1730         self.assertEquals(len(res1), len(res2))
1731
1732         self.assertTrue(res1.count > 0)
1733
1734         self.assertEquals(res1[0]["groupType"][0], "-2147483643")
1735
1736     def test_linked_attributes(self):
1737         """This tests the linked attribute behaviour"""
1738         print "Testing linked attribute behaviour\n"
1739
1740         ldb.add({
1741             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1742             "objectclass": "group"})
1743
1744         # This should not work since "memberOf" is linked to "member"
1745         try:
1746             ldb.add({
1747                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1748                 "objectclass": "user",
1749                 "memberOf": "cn=ldaptestgroup,cn=users," + self.base_dn})
1750         except LdbError, (num, _):
1751             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1752
1753         ldb.add({
1754             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1755             "objectclass": "user"})
1756
1757         m = Message()
1758         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1759         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1760           FLAG_MOD_ADD, "memberOf")
1761         try:
1762             ldb.modify(m)
1763             self.fail()
1764         except LdbError, (num, _):
1765             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1766
1767         m = Message()
1768         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1769         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
1770           FLAG_MOD_ADD, "member")
1771         ldb.modify(m)
1772
1773         m = Message()
1774         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1775         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1776           FLAG_MOD_REPLACE, "memberOf")
1777         try:
1778             ldb.modify(m)
1779             self.fail()
1780         except LdbError, (num, _):
1781             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1782
1783         m = Message()
1784         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1785         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1786           FLAG_MOD_DELETE, "memberOf")
1787         try:
1788             ldb.modify(m)
1789             self.fail()
1790         except LdbError, (num, _):
1791             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1792
1793         m = Message()
1794         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1795         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
1796           FLAG_MOD_DELETE, "member")
1797         ldb.modify(m)
1798
1799         # This should yield no results since the member attribute for
1800         # "ldaptestuser" should have been deleted
1801         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
1802                           scope=SCOPE_BASE,
1803                           expression="(member=cn=ldaptestuser,cn=users," + self.base_dn + ")",
1804                           attrs=[])
1805         self.assertTrue(len(res1) == 0)
1806
1807         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1808
1809         ldb.add({
1810             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1811             "objectclass": "group",
1812             "member": "cn=ldaptestuser,cn=users," + self.base_dn})
1813
1814         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1815
1816         # Make sure that the "member" attribute for "ldaptestuser" has been
1817         # removed
1818         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1819                           scope=SCOPE_BASE, attrs=["member"])
1820         self.assertTrue(len(res) == 1)
1821         self.assertFalse("member" in res[0])
1822
1823         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1824
1825     def test_wkguid(self):
1826         """Test Well known GUID behaviours (including DN+Binary)"""
1827         print "Test Well known GUID behaviours (including DN+Binary)"
1828
1829         res = self.ldb.search(base=("<WKGUID=ab1d30f3768811d1aded00c04fd8d5cd,%s>" % self.base_dn), scope=SCOPE_BASE, attrs=[])
1830         self.assertEquals(len(res), 1)
1831
1832         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd:%s" % res[0].dn))
1833         self.assertEquals(len(res2), 1)
1834
1835         # Prove that the matching rule is over the whole DN+Binary
1836         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd"))
1837         self.assertEquals(len(res2), 0)
1838         # Prove that the matching rule is over the whole DN+Binary
1839         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=%s") % res[0].dn)
1840         self.assertEquals(len(res2), 0)
1841
1842     def test_subschemasubentry(self):
1843         """Test subSchemaSubEntry appears when requested, but not when not requested"""
1844         print "Test subSchemaSubEntry"
1845
1846         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["subSchemaSubEntry"])
1847         self.assertEquals(len(res), 1)
1848         self.assertEquals(res[0]["subSchemaSubEntry"][0], "CN=Aggregate,"+self.schema_dn)
1849
1850         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["*"])
1851         self.assertEquals(len(res), 1)
1852         self.assertTrue("subScheamSubEntry" not in res[0])
1853
1854     def test_all(self):
1855         """Basic tests"""
1856
1857         print "Testing user add"
1858
1859         ldb.add({
1860             "dn": "cn=ldaptestuser,cn=uSers," + self.base_dn,
1861             "objectclass": "user",
1862             "cN": "LDAPtestUSER",
1863             "givenname": "ldap",
1864             "sn": "testy"})
1865
1866         ldb.add({
1867             "dn": "cn=ldaptestgroup,cn=uSers," + self.base_dn,
1868             "objectclass": "group",
1869             "member": "cn=ldaptestuser,cn=useRs," + self.base_dn})
1870
1871         ldb.add({
1872             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1873             "objectclass": "computer",
1874             "cN": "LDAPtestCOMPUTER"})
1875
1876         ldb.add({"dn": "cn=ldaptest2computer,cn=computers," + self.base_dn,
1877             "objectClass": "computer",
1878             "cn": "LDAPtest2COMPUTER",
1879             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT),
1880             "displayname": "ldap testy"})
1881
1882         try:
1883             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1884                      "objectClass": "computer",
1885                      "cn": "LDAPtest2COMPUTER"
1886                      })
1887             self.fail()
1888         except LdbError, (num, _):
1889             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1890
1891         try:
1892             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1893                      "objectClass": "computer",
1894                      "cn": "ldaptestcomputer3",
1895                      "sAMAccountType": str(ATYPE_NORMAL_ACCOUNT)
1896                 })
1897             self.fail()
1898         except LdbError, (num, _):
1899             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1900
1901         ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1902                  "objectClass": "computer",
1903                  "cn": "LDAPtestCOMPUTER3"
1904                  })
1905
1906         print "Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))";
1907         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestcomputer3)(objectClass=user))");
1908         self.assertEquals(len(res), 1, "Found only %d for (&(cn=ldaptestcomputer3)(objectClass=user))" % len(res))
1909
1910         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer3,CN=Computers," + self.base_dn));
1911         self.assertEquals(res[0]["cn"][0], "ldaptestcomputer3");
1912         self.assertEquals(res[0]["name"][0], "ldaptestcomputer3");
1913         self.assertEquals(res[0]["objectClass"][0], "top");
1914         self.assertEquals(res[0]["objectClass"][1], "person");
1915         self.assertEquals(res[0]["objectClass"][2], "organizationalPerson");
1916         self.assertEquals(res[0]["objectClass"][3], "user");
1917         self.assertEquals(res[0]["objectClass"][4], "computer");
1918         self.assertTrue("objectGUID" in res[0])
1919         self.assertTrue("whenCreated" in res[0])
1920         self.assertEquals(res[0]["objectCategory"][0], ("CN=Computer,%s" % ldb.get_schema_basedn()))
1921         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513);
1922         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT);
1923         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE);
1924
1925         delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
1926
1927         print "Testing attribute or value exists behaviour"
1928         try:
1929             ldb.modify_ldif("""
1930 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1931 changetype: modify
1932 replace: servicePrincipalName
1933 servicePrincipalName: host/ldaptest2computer
1934 servicePrincipalName: host/ldaptest2computer
1935 servicePrincipalName: cifs/ldaptest2computer
1936 """)
1937             self.fail()
1938         except LdbError, (num, msg):
1939             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
1940
1941         ldb.modify_ldif("""
1942 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1943 changetype: modify
1944 replace: servicePrincipalName
1945 servicePrincipalName: host/ldaptest2computer
1946 servicePrincipalName: cifs/ldaptest2computer
1947 """)
1948         try:
1949             ldb.modify_ldif("""
1950 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1951 changetype: modify
1952 add: servicePrincipalName
1953 servicePrincipalName: host/ldaptest2computer
1954 """)
1955             self.fail()
1956         except LdbError, (num, msg):
1957             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
1958
1959         print "Testing ranged results"
1960         ldb.modify_ldif("""
1961 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1962 changetype: modify
1963 replace: servicePrincipalName
1964 """)
1965
1966         ldb.modify_ldif("""
1967 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1968 changetype: modify
1969 add: servicePrincipalName
1970 servicePrincipalName: host/ldaptest2computer0
1971 servicePrincipalName: host/ldaptest2computer1
1972 servicePrincipalName: host/ldaptest2computer2
1973 servicePrincipalName: host/ldaptest2computer3
1974 servicePrincipalName: host/ldaptest2computer4
1975 servicePrincipalName: host/ldaptest2computer5
1976 servicePrincipalName: host/ldaptest2computer6
1977 servicePrincipalName: host/ldaptest2computer7
1978 servicePrincipalName: host/ldaptest2computer8
1979 servicePrincipalName: host/ldaptest2computer9
1980 servicePrincipalName: host/ldaptest2computer10
1981 servicePrincipalName: host/ldaptest2computer11
1982 servicePrincipalName: host/ldaptest2computer12
1983 servicePrincipalName: host/ldaptest2computer13
1984 servicePrincipalName: host/ldaptest2computer14
1985 servicePrincipalName: host/ldaptest2computer15
1986 servicePrincipalName: host/ldaptest2computer16
1987 servicePrincipalName: host/ldaptest2computer17
1988 servicePrincipalName: host/ldaptest2computer18
1989 servicePrincipalName: host/ldaptest2computer19
1990 servicePrincipalName: host/ldaptest2computer20
1991 servicePrincipalName: host/ldaptest2computer21
1992 servicePrincipalName: host/ldaptest2computer22
1993 servicePrincipalName: host/ldaptest2computer23
1994 servicePrincipalName: host/ldaptest2computer24
1995 servicePrincipalName: host/ldaptest2computer25
1996 servicePrincipalName: host/ldaptest2computer26
1997 servicePrincipalName: host/ldaptest2computer27
1998 servicePrincipalName: host/ldaptest2computer28
1999 servicePrincipalName: host/ldaptest2computer29
2000 """)
2001
2002         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE,
2003                          attrs=["servicePrincipalName;range=0-*"])
2004         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2005         #print len(res[0]["servicePrincipalName;range=0-*"])
2006         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
2007
2008         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
2009         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2010             # print res[0]["servicePrincipalName;range=0-19"].length
2011         self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
2012
2013
2014         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
2015         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2016         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
2017
2018         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
2019         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2020         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
2021
2022         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
2023         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2024         self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
2025
2026
2027         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
2028         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2029         self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
2030         # pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
2031
2032         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
2033         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2034         self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
2035             # print res[0]["servicePrincipalName;range=11-*"][18]
2036             # print pos_11
2037             # self.assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11)
2038
2039         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
2040         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2041         self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
2042             # self.assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11)
2043
2044         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
2045         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
2046             # print res[0]["servicePrincipalName"][18]
2047             # print pos_11
2048         self.assertEquals(len(res[0]["servicePrincipalName"]), 30)
2049             # self.assertEquals(res[0]["servicePrincipalName"][18], pos_11)
2050
2051         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2052         ldb.add({
2053             "dn": "cn=ldaptestuser2,cn=useRs," + self.base_dn,
2054             "objectClass": "user",
2055             "cn": "LDAPtestUSER2",
2056             "givenname": "testy",
2057             "sn": "ldap user2"})
2058
2059         print "Testing Ambigious Name Resolution"
2060         # Testing ldb.search for (&(anr=ldap testy)(objectClass=user))
2061         res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))")
2062         self.assertEquals(len(res), 3, "Found only %d of 3 for (&(anr=ldap testy)(objectClass=user))" % len(res))
2063
2064         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
2065         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
2066         self.assertEquals(len(res), 2, "Found only %d of 2 for (&(anr=testy ldap)(objectClass=user))" % len(res))
2067
2068         # Testing ldb.search for (&(anr=ldap)(objectClass=user))
2069         res = ldb.search(expression="(&(anr=ldap)(objectClass=user))")
2070         self.assertEquals(len(res), 4, "Found only %d of 4 for (&(anr=ldap)(objectClass=user))" % len(res))
2071
2072         # Testing ldb.search for (&(anr==ldap)(objectClass=user))
2073         res = ldb.search(expression="(&(anr==ldap)(objectClass=user))")
2074         self.assertEquals(len(res), 1, "Could not find (&(anr==ldap)(objectClass=user)). Found only %d for (&(anr=ldap)(objectClass=user))" % len(res))
2075
2076         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
2077         self.assertEquals(res[0]["cn"][0], "ldaptestuser")
2078         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
2079
2080         # Testing ldb.search for (&(anr=testy)(objectClass=user))
2081         res = ldb.search(expression="(&(anr=testy)(objectClass=user))")
2082         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res))
2083
2084         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
2085         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
2086         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res))
2087
2088         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
2089 # this test disabled for the moment, as anr with == tests are not understood
2090 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
2091 #        self.assertEquals(len(res), 1, "Found only %d for (&(anr==testy ldap)(objectClass=user))" % len(res))
2092
2093 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
2094 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
2095 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
2096
2097         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
2098 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
2099 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap)(objectClass=user))")
2100
2101 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
2102 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
2103 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
2104
2105         # Testing ldb.search for (&(anr=testy ldap user)(objectClass=user))
2106         res = ldb.search(expression="(&(anr=testy ldap user)(objectClass=user))")
2107         self.assertEquals(len(res), 1, "Could not find (&(anr=testy ldap user)(objectClass=user))")
2108
2109         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2110         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
2111         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
2112
2113         # Testing ldb.search for (&(anr==testy ldap user2)(objectClass=user))
2114 #        res = ldb.search(expression="(&(anr==testy ldap user2)(objectClass=user))")
2115 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap user2)(objectClass=user))")
2116
2117         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2118         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
2119         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
2120
2121         # Testing ldb.search for (&(anr==ldap user2)(objectClass=user))
2122 #        res = ldb.search(expression="(&(anr==ldap user2)(objectClass=user))")
2123 #        self.assertEquals(len(res), 1, "Could not find (&(anr==ldap user2)(objectClass=user))")
2124
2125         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2126         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
2127         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
2128
2129         # Testing ldb.search for (&(anr==not ldap user2)(objectClass=user))
2130 #        res = ldb.search(expression="(&(anr==not ldap user2)(objectClass=user))")
2131 #        self.assertEquals(len(res), 0, "Must not find (&(anr==not ldap user2)(objectClass=user))")
2132
2133         # Testing ldb.search for (&(anr=not ldap user2)(objectClass=user))
2134         res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))")
2135         self.assertEquals(len(res), 0, "Must not find (&(anr=not ldap user2)(objectClass=user))")
2136
2137         # Testing ldb.search for (&(anr="testy ldap")(objectClass=user)) (ie, with quotes)
2138 #        res = ldb.search(expression="(&(anr==\"testy ldap\")(objectClass=user))")
2139 #        self.assertEquals(len(res), 0, "Found (&(anr==\"testy ldap\")(objectClass=user))")
2140
2141         print "Testing Renames"
2142
2143         attrs = ["objectGUID", "objectSid"]
2144         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
2145         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
2146         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
2147
2148         # Check rename works with extended/alternate DN forms
2149         ldb.rename("<SID=" + ldb.schema_format_value("objectSID", res_user[0]["objectSID"][0]) + ">" , "cn=ldaptestUSER3,cn=users," + self.base_dn)
2150
2151         print "Testing ldb.search for (&(cn=ldaptestuser3)(objectClass=user))"
2152         res = ldb.search(expression="(&(cn=ldaptestuser3)(objectClass=user))")
2153         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser3)(objectClass=user))")
2154
2155         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
2156         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
2157         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
2158
2159          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"
2160         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
2161         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
2162
2163         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
2164         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
2165         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
2166
2167          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"
2168         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
2169         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
2170
2171         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
2172         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
2173         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
2174
2175          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"
2176         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
2177         self.assertEquals(len(res), 0, "(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
2178
2179         print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ") - should not work"
2180         res = ldb.search(expression="(dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
2181         self.assertEquals(len(res), 0, "Could find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
2182
2183         print "Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
2184         res = ldb.search(expression="(distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
2185         self.assertEquals(len(res), 1, "Could not find (distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
2186         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
2187         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
2188         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
2189
2190         # ensure we cannot add it again
2191         try:
2192             ldb.add({"dn": "cn=ldaptestuser3,cn=userS," + self.base_dn,
2193                       "objectClass": "user",
2194                       "cn": "LDAPtestUSER3"})
2195             self.fail()
2196         except LdbError, (num, _):
2197             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
2198
2199         # rename back
2200         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
2201
2202         # ensure we cannot rename it twice
2203         try:
2204             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn,
2205                        "cn=ldaptestuser2,cn=users," + self.base_dn)
2206             self.fail()
2207         except LdbError, (num, _):
2208             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
2209
2210         # ensure can now use that name
2211         ldb.add({"dn": "cn=ldaptestuser3,cn=users," + self.base_dn,
2212                       "objectClass": "user",
2213                       "cn": "LDAPtestUSER3"})
2214
2215         # ensure we now cannot rename
2216         try:
2217             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
2218             self.fail()
2219         except LdbError, (num, _):
2220             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
2221         try:
2222             ldb.rename("cn=ldaptestuser3,cn=users,%s" % self.base_dn, "cn=ldaptestuser3,%s" % ldb.get_config_basedn())
2223             self.fail()
2224         except LdbError, (num, _):
2225             self.assertTrue(num in (71, 64))
2226
2227         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser5,cn=users," + self.base_dn)
2228
2229         ldb.delete("cn=ldaptestuser5,cn=users," + self.base_dn)
2230
2231         delete_force(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
2232
2233         ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn, "cn=ldaptestgroup2,cn=users," + self.base_dn)
2234
2235         print "Testing subtree renames"
2236
2237         ldb.add({"dn": "cn=ldaptestcontainer," + self.base_dn,
2238                  "objectClass": "container"})
2239
2240         ldb.add({"dn": "CN=ldaptestuser4,CN=ldaptestcontainer," + self.base_dn,
2241                  "objectClass": "user",
2242                  "cn": "LDAPtestUSER4"})
2243
2244         # Here we don't enforce these hard "description" constraints
2245         ldb.modify_ldif("""
2246 dn: cn=ldaptestcontainer,""" + self.base_dn + """
2247 changetype: modify
2248 replace: description
2249 description: desc1
2250 description: desc2
2251 """)
2252
2253         ldb.modify_ldif("""
2254 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2255 changetype: modify
2256 add: member
2257 member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
2258 member: cn=ldaptestcomputer,cn=computers,""" + self.base_dn + """
2259 member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """
2260 """)
2261
2262         print "Testing ldb.rename of cn=ldaptestcontainer," + self.base_dn + " to cn=ldaptestcontainer2," + self.base_dn
2263         ldb.rename("CN=ldaptestcontainer," + self.base_dn, "CN=ldaptestcontainer2," + self.base_dn)
2264
2265         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user))"
2266         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))")
2267         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user))")
2268
2269         print "Testing subtree ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
2270         try:
2271             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
2272                     expression="(&(cn=ldaptestuser4)(objectClass=user))",
2273                     scope=SCOPE_SUBTREE)
2274             self.fail(res)
2275         except LdbError, (num, _):
2276             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
2277
2278         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
2279         try:
2280             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
2281                     expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_ONELEVEL)
2282             self.fail()
2283         except LdbError, (num, _):
2284             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
2285
2286         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in renamed container"
2287         res = ldb.search("cn=ldaptestcontainer2," + self.base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_SUBTREE)
2288         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user)) under cn=ldaptestcontainer2," + self.base_dn)
2289
2290         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
2291         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2292
2293         time.sleep(4)
2294
2295         print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"
2296         res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE)
2297         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?")
2298
2299         print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn
2300         try:
2301             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn)
2302             self.fail()
2303         except LdbError, (num, _):
2304             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2305
2306         print "Testing ldb.rename (into non-existent container) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn
2307         try:
2308             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn)
2309             self.fail()
2310         except LdbError, (num, _):
2311             self.assertTrue(num in (ERR_UNWILLING_TO_PERFORM, ERR_OTHER))
2312
2313         print "Testing delete (should fail, not a leaf node) of renamed cn=ldaptestcontainer2," + self.base_dn
2314         try:
2315             ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
2316             self.fail()
2317         except LdbError, (num, _):
2318             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
2319
2320         print "Testing base ldb.search for CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn
2321         res = ldb.search(expression="(objectclass=*)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
2322         self.assertEquals(len(res), 1)
2323         res = ldb.search(expression="(cn=ldaptestuser40)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
2324         self.assertEquals(len(res), 0)
2325
2326         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
2327         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_ONELEVEL)
2328         self.assertEquals(len(res), 1)
2329
2330         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
2331         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_SUBTREE)
2332         self.assertEquals(len(res), 1)
2333
2334         print "Testing delete of subtree renamed "+("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn)
2335         ldb.delete(("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
2336         print "Testing delete of renamed cn=ldaptestcontainer2," + self.base_dn
2337         ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
2338
2339         ldb.add({"dn": "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
2340
2341         ldb.add({"dn": "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
2342
2343         print "Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))"
2344         res = ldb.search(expression="(&(cn=ldaptestuser)(objectClass=user))")
2345         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
2346
2347         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
2348         self.assertEquals(str(res[0]["cn"]), "ldaptestuser")
2349         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
2350         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user"]))
2351         self.assertTrue("objectGUID" in res[0])
2352         self.assertTrue("whenCreated" in res[0])
2353         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Person,%s" % ldb.get_schema_basedn()))
2354         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
2355         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
2356         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2357         self.assertEquals(len(res[0]["memberOf"]), 1)
2358
2359         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=cn=person,%s))" % ldb.get_schema_basedn()
2360         res2 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=cn=person,%s))" % ldb.get_schema_basedn())
2361         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=cn=person,%s))" % ldb.get_schema_basedn())
2362
2363         self.assertEquals(res[0].dn, res2[0].dn)
2364
2365         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon))"
2366         res3 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
2367         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)): matched %d" % len(res3))
2368
2369         self.assertEquals(res[0].dn, res3[0].dn)
2370
2371         if gc_ldb is not None:
2372             print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog"
2373             res3gc = gc_ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
2374             self.assertEquals(len(res3gc), 1)
2375
2376             self.assertEquals(res[0].dn, res3gc[0].dn)
2377
2378         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in with 'phantom root' control"
2379
2380         if gc_ldb is not None:
2381             res3control = gc_ldb.search(self.base_dn, expression="(&(cn=ldaptestuser)(objectCategory=PerSon))", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
2382             self.assertEquals(len(res3control), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog")
2383
2384             self.assertEquals(res[0].dn, res3control[0].dn)
2385
2386         ldb.delete(res[0].dn)
2387
2388         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))"
2389         res = ldb.search(expression="(&(cn=ldaptestcomputer)(objectClass=user))")
2390         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
2391
2392         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer,CN=Computers," + self.base_dn))
2393         self.assertEquals(str(res[0]["cn"]), "ldaptestcomputer")
2394         self.assertEquals(str(res[0]["name"]), "ldaptestcomputer")
2395         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user", "computer"]))
2396         self.assertTrue("objectGUID" in res[0])
2397         self.assertTrue("whenCreated" in res[0])
2398         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Computer,%s" % ldb.get_schema_basedn()))
2399         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513)
2400         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
2401         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
2402         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2403         self.assertEquals(len(res[0]["memberOf"]), 1)
2404
2405         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,%s))" % ldb.get_schema_basedn()
2406         res2 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,%s))" % ldb.get_schema_basedn())
2407         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,%s))" % ldb.get_schema_basedn())
2408
2409         self.assertEquals(res[0].dn, res2[0].dn)
2410
2411         if gc_ldb is not None:
2412             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,%s)) in Global Catalog" % gc_ldb.get_schema_basedn()
2413             res2gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,%s))" % gc_ldb.get_schema_basedn())
2414             self.assertEquals(len(res2gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,%s)) In Global Catalog" % gc_ldb.get_schema_basedn())
2415
2416             self.assertEquals(res[0].dn, res2gc[0].dn)
2417
2418         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER))"
2419         res3 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2420         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2421
2422         self.assertEquals(res[0].dn, res3[0].dn)
2423
2424         if gc_ldb is not None:
2425             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog"
2426             res3gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2427             self.assertEquals(len(res3gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog")
2428
2429             self.assertEquals(res[0].dn, res3gc[0].dn)
2430
2431         print "Testing ldb.search for (&(cn=ldaptestcomp*r)(objectCategory=compuTER))"
2432         res4 = ldb.search(expression="(&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
2433         self.assertEquals(len(res4), 1, "Could not find (&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
2434
2435         self.assertEquals(res[0].dn, res4[0].dn)
2436
2437         print "Testing ldb.search for (&(cn=ldaptestcomput*)(objectCategory=compuTER))"
2438         res5 = ldb.search(expression="(&(cn=ldaptestcomput*)(objectCategory=compuTER))")
2439         self.assertEquals(len(res5), 1, "Could not find (&(cn=ldaptestcomput*)(objectCategory=compuTER))")
2440
2441         self.assertEquals(res[0].dn, res5[0].dn)
2442
2443         print "Testing ldb.search for (&(cn=*daptestcomputer)(objectCategory=compuTER))"
2444         res6 = ldb.search(expression="(&(cn=*daptestcomputer)(objectCategory=compuTER))")
2445         self.assertEquals(len(res6), 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))")
2446
2447         self.assertEquals(res[0].dn, res6[0].dn)
2448
2449         ldb.delete("<GUID=" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + ">")
2450
2451         print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))"
2452         res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))")
2453         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptest2computer)(objectClass=user))")
2454
2455         self.assertEquals(str(res[0].dn), "CN=ldaptest2computer,CN=Computers," + self.base_dn)
2456         self.assertEquals(str(res[0]["cn"]), "ldaptest2computer")
2457         self.assertEquals(str(res[0]["name"]), "ldaptest2computer")
2458         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user", "computer"])
2459         self.assertTrue("objectGUID" in res[0])
2460         self.assertTrue("whenCreated" in res[0])
2461         self.assertEquals(res[0]["objectCategory"][0], "CN=Computer,%s" % ldb.get_schema_basedn())
2462         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST)
2463         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT)
2464
2465         ldb.delete("<SID=" + ldb.schema_format_value("objectSID", res[0]["objectSID"][0]) + ">")
2466
2467         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "memberOf", "allowedAttributes", "allowedAttributesEffective"]
2468         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
2469         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
2470         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
2471
2472         self.assertEquals(str(res_user[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2473         self.assertEquals(str(res_user[0]["cn"]), "ldaptestuser2")
2474         self.assertEquals(str(res_user[0]["name"]), "ldaptestuser2")
2475         self.assertEquals(list(res_user[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
2476         self.assertTrue("objectSid" in res_user[0])
2477         self.assertTrue("objectGUID" in res_user[0])
2478         self.assertTrue("whenCreated" in res_user[0])
2479         self.assertTrue("nTSecurityDescriptor" in res_user[0])
2480         self.assertTrue("allowedAttributes" in res_user[0])
2481         self.assertTrue("allowedAttributesEffective" in res_user[0])
2482         self.assertEquals(res_user[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2483
2484         ldaptestuser2_sid = res_user[0]["objectSid"][0]
2485         ldaptestuser2_guid = res_user[0]["objectGUID"][0]
2486
2487         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "member", "allowedAttributes", "allowedAttributesEffective"]
2488         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))"
2489         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2490         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2491
2492         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2493         self.assertEquals(str(res[0]["cn"]), "ldaptestgroup2")
2494         self.assertEquals(str(res[0]["name"]), "ldaptestgroup2")
2495         self.assertEquals(list(res[0]["objectClass"]), ["top", "group"])
2496         self.assertTrue("objectGUID" in res[0])
2497         self.assertTrue("objectSid" in res[0])
2498         self.assertTrue("whenCreated" in res[0])
2499         self.assertTrue("nTSecurityDescriptor" in res[0])
2500         self.assertTrue("allowedAttributes" in res[0])
2501         self.assertTrue("allowedAttributesEffective" in res[0])
2502         memberUP = []
2503         for m in res[0]["member"]:
2504             memberUP.append(m.upper())
2505         self.assertTrue(("CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
2506
2507         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs, controls=["extended_dn:1:1"])
2508         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2509
2510         print res[0]["member"]
2511         memberUP = []
2512         for m in res[0]["member"]:
2513             memberUP.append(m.upper())
2514         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()
2515
2516         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)
2517
2518         print "Quicktest for linked attributes"
2519         ldb.modify_ldif("""
2520 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2521 changetype: modify
2522 replace: member
2523 member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
2524 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2525 """)
2526
2527         ldb.modify_ldif("""
2528 dn: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
2529 changetype: modify
2530 replace: member
2531 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2532 """)
2533
2534         ldb.modify_ldif("""
2535 dn: <SID=""" + ldb.schema_format_value("objectSid", res[0]["objectSid"][0]) + """>
2536 changetype: modify
2537 delete: member
2538 """)
2539
2540         ldb.modify_ldif("""
2541 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2542 changetype: modify
2543 add: member
2544 member: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
2545 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2546 """)
2547
2548         ldb.modify_ldif("""
2549 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2550 changetype: modify
2551 replace: member
2552 """)
2553
2554         ldb.modify_ldif("""
2555 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2556 changetype: modify
2557 add: member
2558 member: <SID=""" + ldb.schema_format_value("objectSid", res_user[0]["objectSid"][0]) + """>
2559 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2560 """)
2561
2562         ldb.modify_ldif("""
2563 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2564 changetype: modify
2565 delete: member
2566 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2567 """)
2568
2569         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2570         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2571
2572         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2573         self.assertEquals(res[0]["member"][0], ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2574         self.assertEquals(len(res[0]["member"]), 1)
2575
2576         ldb.delete(("CN=ldaptestuser2,CN=Users," + self.base_dn))
2577
2578         time.sleep(4)
2579
2580         attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]
2581         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
2582         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2583         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete")
2584
2585         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2586         self.assertTrue("member" not in res[0])
2587
2588         print "Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))"
2589         res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2590         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2591         res = ldb.search(expression="(&(cn=ldaptestutf8user èùéìòà)(objectclass=user))")
2592         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2593
2594         self.assertEquals(str(res[0].dn), ("CN=ldaptestutf8user èùéìòà,CN=Users," + self.base_dn))
2595         self.assertEquals(str(res[0]["cn"]), "ldaptestutf8user èùéìòà")
2596         self.assertEquals(str(res[0]["name"]), "ldaptestutf8user èùéìòà")
2597         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
2598         self.assertTrue("objectGUID" in res[0])
2599         self.assertTrue("whenCreated" in res[0])
2600
2601         # delete "ldaptestutf8user"
2602         ldb.delete(res[0].dn)
2603
2604         print "Testing ldb.search for (&(cn=ldaptestutf8user2*)(objectClass=user))"
2605         res = ldb.search(expression="(&(cn=ldaptestutf8user2*)(objectClass=user))")
2606         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user2*)(objectClass=user))")
2607
2608         print "Testing ldb.search for (&(cn=ldaptestutf8user2  ÈÙÉÌÒÀ)(objectClass=user))"
2609         res = ldb.search(expression="(&(cn=ldaptestutf8user2  ÈÙÉÌÒÀ)(objectClass=user))")
2610         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user2  ÈÙÉÌÒÀ)(objectClass=user))")
2611
2612         # delete "ldaptestutf8user2 "
2613         ldb.delete(res[0].dn)
2614
2615         ldb.delete(("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2616
2617         print "Testing that we can't get at the configuration DN from the main search base"
2618         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2619         self.assertEquals(len(res), 0)
2620
2621         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"
2622         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
2623         self.assertTrue(len(res) > 0)
2624
2625         if gc_ldb is not None:
2626             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"
2627
2628             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:0"])
2629             self.assertTrue(len(res) > 0)
2630
2631             print "Testing that we do find configuration elements in the global catlog"
2632             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2633             self.assertTrue(len(res) > 0)
2634
2635             print "Testing that we do find configuration elements and user elements at the same time"
2636             res = gc_ldb.search(self.base_dn, expression="(|(objectClass=crossRef)(objectClass=person))", scope=SCOPE_SUBTREE, attrs=["cn"])
2637             self.assertTrue(len(res) > 0)
2638
2639             print "Testing that we do find configuration elements in the global catlog, with the configuration basedn"
2640             res = gc_ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2641             self.assertTrue(len(res) > 0)
2642
2643         print "Testing that we can get at the configuration DN on the main LDAP port"
2644         res = ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2645         self.assertTrue(len(res) > 0)
2646
2647         print "Testing objectCategory canonacolisation"
2648         res = ldb.search(self.configuration_dn, expression="objectCategory=ntDsDSA", scope=SCOPE_SUBTREE, attrs=["cn"])
2649         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=ntDsDSA")
2650         self.assertTrue(len(res) != 0)
2651
2652         res = ldb.search(self.configuration_dn, expression="objectCategory=CN=ntDs-DSA," + self.schema_dn, scope=SCOPE_SUBTREE, attrs=["cn"])
2653         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=CN=ntDs-DSA," + self.schema_dn)
2654         self.assertTrue(len(res) != 0)
2655
2656         print "Testing objectClass attribute order on "+ self.base_dn
2657         res = ldb.search(expression="objectClass=domain", base=self.base_dn,
2658                          scope=SCOPE_BASE, attrs=["objectClass"])
2659         self.assertEquals(len(res), 1)
2660
2661         self.assertEquals(list(res[0]["objectClass"]), ["top", "domain", "domainDNS"])
2662
2663     #  check enumeration
2664
2665         print "Testing ldb.search for objectCategory=person"
2666         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"])
2667         self.assertTrue(len(res) > 0)
2668
2669         print "Testing ldb.search for objectCategory=person with domain scope control"
2670         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2671         self.assertTrue(len(res) > 0)
2672
2673         print "Testing ldb.search for objectCategory=user"
2674         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"])
2675         self.assertTrue(len(res) > 0)
2676
2677         print "Testing ldb.search for objectCategory=user with domain scope control"
2678         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2679         self.assertTrue(len(res) > 0)
2680
2681         print "Testing ldb.search for objectCategory=group"
2682         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"])
2683         self.assertTrue(len(res) > 0)
2684
2685         print "Testing ldb.search for objectCategory=group with domain scope control"
2686         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2687         self.assertTrue(len(res) > 0)
2688
2689         print "Testing creating a user with the posixAccount objectClass"
2690         self.ldb.add_ldif("""dn: cn=posixuser,CN=Users,%s
2691 objectClass: top
2692 objectClass: person
2693 objectClass: posixAccount
2694 objectClass: user
2695 objectClass: organizationalPerson
2696 cn: posixuser
2697 uid: posixuser
2698 sn: posixuser
2699 uidNumber: 10126
2700 gidNumber: 10126
2701 homeDirectory: /home/posixuser
2702 loginShell: /bin/bash
2703 gecos: Posix User;;;
2704 description: A POSIX user"""% (self.base_dn))
2705
2706         print "Testing removing the posixAccount objectClass from an existing user"
2707         self.ldb.modify_ldif("""dn: cn=posixuser,CN=Users,%s
2708 changetype: modify
2709 delete: objectClass
2710 objectClass: posixAccount"""% (self.base_dn))
2711
2712         print "Testing adding the posixAccount objectClass to an existing user"
2713         self.ldb.modify_ldif("""dn: cn=posixuser,CN=Users,%s
2714 changetype: modify
2715 add: objectClass
2716 objectClass: posixAccount"""% (self.base_dn))
2717
2718         delete_force(self.ldb, "cn=posixuser,cn=users," + self.base_dn)
2719         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2720         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2721         delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
2722         delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
2723         delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
2724         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
2725         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2726         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
2727         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2728         delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
2729         delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
2730         delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
2731         delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
2732         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
2733         delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
2734
2735     def test_security_descriptor_add(self):
2736         """ Testing ldb.add_ldif() for nTSecurityDescriptor """
2737         user_name = "testdescriptoruser1"
2738         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2739         #
2740         # Test an empty security descriptor (naturally this shouldn't work)
2741         #
2742         delete_force(self.ldb, user_dn)
2743         try:
2744             self.ldb.add({ "dn": user_dn,
2745                            "objectClass": "user",
2746                            "sAMAccountName": user_name,
2747                            "nTSecurityDescriptor": [] })
2748             self.fail()
2749         except LdbError, (num, _):
2750             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2751         finally:
2752             delete_force(self.ldb, user_dn)
2753         #
2754         # Test add_ldif() with SDDL security descriptor input
2755         #
2756         try:
2757             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2758             self.ldb.add_ldif("""
2759 dn: """ + user_dn + """
2760 objectclass: user
2761 sAMAccountName: """ + user_name + """
2762 nTSecurityDescriptor: """ + sddl)
2763             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2764             desc = res[0]["nTSecurityDescriptor"][0]
2765             desc = ndr_unpack( security.descriptor, desc )
2766             desc_sddl = desc.as_sddl( self.domain_sid )
2767             self.assertEqual(desc_sddl, sddl)
2768         finally:
2769             delete_force(self.ldb, user_dn)
2770         #
2771         # Test add_ldif() with BASE64 security descriptor
2772         #
2773         try:
2774             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2775             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2776             desc_binary = ndr_pack(desc)
2777             desc_base64 = base64.b64encode(desc_binary)
2778             self.ldb.add_ldif("""
2779 dn: """ + user_dn + """
2780 objectclass: user
2781 sAMAccountName: """ + user_name + """
2782 nTSecurityDescriptor:: """ + desc_base64)
2783             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2784             desc = res[0]["nTSecurityDescriptor"][0]
2785             desc = ndr_unpack(security.descriptor, desc)
2786             desc_sddl = desc.as_sddl(self.domain_sid)
2787             self.assertEqual(desc_sddl, sddl)
2788         finally:
2789             delete_force(self.ldb, user_dn)
2790
2791     def test_security_descriptor_add_neg(self):
2792         """Test add_ldif() with BASE64 security descriptor input using WRONG domain SID
2793             Negative test
2794         """
2795         user_name = "testdescriptoruser1"
2796         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2797         delete_force(self.ldb, user_dn)
2798         try:
2799             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2800             desc = security.descriptor.from_sddl(sddl, security.dom_sid('S-1-5-21'))
2801             desc_base64 = base64.b64encode( ndr_pack(desc) )
2802             self.ldb.add_ldif("""
2803 dn: """ + user_dn + """
2804 objectclass: user
2805 sAMAccountName: """ + user_name + """
2806 nTSecurityDescriptor:: """ + desc_base64)
2807             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2808             self.assertTrue("nTSecurityDescriptor" in res[0])
2809         finally:
2810             delete_force(self.ldb, user_dn)
2811
2812     def test_security_descriptor_modify(self):
2813         """ Testing ldb.modify_ldif() for nTSecurityDescriptor """
2814         user_name = "testdescriptoruser2"
2815         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2816         #
2817         # Test an empty security descriptor (naturally this shouldn't work)
2818         #
2819         delete_force(self.ldb, user_dn)
2820         self.ldb.add({ "dn": user_dn,
2821                        "objectClass": "user",
2822                        "sAMAccountName": user_name })
2823
2824         m = Message()
2825         m.dn = Dn(ldb, user_dn)
2826         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_ADD,
2827                                                    "nTSecurityDescriptor")
2828         try:
2829             self.ldb.modify(m)
2830             self.fail()
2831         except LdbError, (num, _):
2832             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2833
2834         m = Message()
2835         m.dn = Dn(ldb, user_dn)
2836         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_REPLACE,
2837                                                    "nTSecurityDescriptor")
2838         try:
2839             self.ldb.modify(m)
2840             self.fail()
2841         except LdbError, (num, _):
2842             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2843
2844         m = Message()
2845         m.dn = Dn(ldb, user_dn)
2846         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_DELETE,
2847                                                    "nTSecurityDescriptor")
2848         try:
2849             self.ldb.modify(m)
2850             self.fail()
2851         except LdbError, (num, _):
2852             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2853
2854         delete_force(self.ldb, user_dn)
2855         #
2856         # Test modify_ldif() with SDDL security descriptor input
2857         # Add ACE to the original descriptor test
2858         #
2859         try:
2860             self.ldb.add_ldif("""
2861 dn: """ + user_dn + """
2862 objectclass: user
2863 sAMAccountName: """ + user_name)
2864             # Modify descriptor
2865             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2866             desc = res[0]["nTSecurityDescriptor"][0]
2867             desc = ndr_unpack(security.descriptor, desc)
2868             desc_sddl = desc.as_sddl(self.domain_sid)
2869             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
2870             mod = """
2871 dn: """ + user_dn + """
2872 changetype: modify
2873 replace: nTSecurityDescriptor
2874 nTSecurityDescriptor: """ + sddl
2875             self.ldb.modify_ldif(mod)
2876             # Read modified descriptor
2877             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2878             desc = res[0]["nTSecurityDescriptor"][0]
2879             desc = ndr_unpack(security.descriptor, desc)
2880             desc_sddl = desc.as_sddl(self.domain_sid)
2881             self.assertEqual(desc_sddl, sddl)
2882         finally:
2883             delete_force(self.ldb, user_dn)
2884         #
2885         # Test modify_ldif() with SDDL security descriptor input
2886         # New desctiptor test
2887         #
2888         try:
2889             self.ldb.add_ldif("""
2890 dn: """ + user_dn + """
2891 objectclass: user
2892 sAMAccountName: """ + user_name)
2893             # Modify descriptor
2894             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2895             mod = """
2896 dn: """ + user_dn + """
2897 changetype: modify
2898 replace: nTSecurityDescriptor
2899 nTSecurityDescriptor: """ + sddl
2900             self.ldb.modify_ldif(mod)
2901             # Read modified descriptor
2902             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2903             desc = res[0]["nTSecurityDescriptor"][0]
2904             desc = ndr_unpack(security.descriptor, desc)
2905             desc_sddl = desc.as_sddl(self.domain_sid)
2906             self.assertEqual(desc_sddl, sddl)
2907         finally:
2908             delete_force(self.ldb, user_dn)
2909         #
2910         # Test modify_ldif() with BASE64 security descriptor input
2911         # Add ACE to the original descriptor test
2912         #
2913         try:
2914             self.ldb.add_ldif("""
2915 dn: """ + user_dn + """
2916 objectclass: user
2917 sAMAccountName: """ + user_name)
2918             # Modify descriptor
2919             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2920             desc = res[0]["nTSecurityDescriptor"][0]
2921             desc = ndr_unpack(security.descriptor, desc)
2922             desc_sddl = desc.as_sddl(self.domain_sid)
2923             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
2924             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2925             desc_base64 = base64.b64encode(ndr_pack(desc))
2926             mod = """
2927 dn: """ + user_dn + """
2928 changetype: modify
2929 replace: nTSecurityDescriptor
2930 nTSecurityDescriptor:: """ + desc_base64
2931             self.ldb.modify_ldif(mod)
2932             # Read modified descriptor
2933             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2934             desc = res[0]["nTSecurityDescriptor"][0]
2935             desc = ndr_unpack(security.descriptor, desc)
2936             desc_sddl = desc.as_sddl(self.domain_sid)
2937             self.assertEqual(desc_sddl, sddl)
2938         finally:
2939             delete_force(self.ldb, user_dn)
2940         #
2941         # Test modify_ldif() with BASE64 security descriptor input
2942         # New descriptor test
2943         #
2944         try:
2945             delete_force(self.ldb, user_dn)
2946             self.ldb.add_ldif("""
2947 dn: """ + user_dn + """
2948 objectclass: user
2949 sAMAccountName: """ + user_name)
2950             # Modify descriptor
2951             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2952             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2953             desc_base64 = base64.b64encode(ndr_pack(desc))
2954             mod = """
2955 dn: """ + user_dn + """
2956 changetype: modify
2957 replace: nTSecurityDescriptor
2958 nTSecurityDescriptor:: """ + desc_base64
2959             self.ldb.modify_ldif(mod)
2960             # Read modified descriptor
2961             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2962             desc = res[0]["nTSecurityDescriptor"][0]
2963             desc = ndr_unpack(security.descriptor, desc)
2964             desc_sddl = desc.as_sddl(self.domain_sid)
2965             self.assertEqual(desc_sddl, sddl)
2966         finally:
2967             delete_force(self.ldb, user_dn)
2968
2969     def test_dsheuristics(self):
2970         """Tests the 'dSHeuristics' attribute"""
2971         print "Tests the 'dSHeuristics' attribute"
2972
2973         # Get the current value to restore it later
2974         dsheuristics = self.ldb.get_dsheuristics()
2975         # Perform the length checks: for each decade (except the 0th) we need
2976         # the first index to be the number. This goes till the 9th one, beyond
2977         # there does not seem to be another limitation.
2978         try:
2979             dshstr = ""
2980             for i in range(1,11):
2981                 # This is in the range
2982                 self.ldb.set_dsheuristics(dshstr + "x")
2983                 self.ldb.set_dsheuristics(dshstr + "xxxxx")
2984                 dshstr = dshstr + "xxxxxxxxx"
2985                 if i < 10:
2986                     # Not anymore in the range, new decade specifier needed
2987                     try:
2988                         self.ldb.set_dsheuristics(dshstr + "x")
2989                         self.fail()
2990                     except LdbError, (num, _):
2991                         self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2992                     dshstr = dshstr + str(i)
2993                 else:
2994                     # There does not seem to be an upper limit
2995                     self.ldb.set_dsheuristics(dshstr + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
2996             # apart from the above, all char values are accepted
2997             self.ldb.set_dsheuristics("123ABC-+!1asdfg@#^")
2998             self.assertEquals(self.ldb.get_dsheuristics(), "123ABC-+!1asdfg@#^")
2999         finally:
3000             # restore old value
3001             self.ldb.set_dsheuristics(dsheuristics)
3002
3003     def test_ldapControlReturn(self):
3004         """Testing that if we request a control that return a control it
3005            really return something"""
3006         res = self.ldb.search(attrs=["cn"],
3007                               controls=["paged_results:1:10"])
3008         self.assertEquals(len(res.controls), 1)
3009         self.assertEquals(res.controls[0].oid, "1.2.840.113556.1.4.319")
3010         s = str(res.controls[0])
3011
3012     def test_operational(self):
3013         """Tests operational attributes"""
3014         print "Tests operational attributes"
3015
3016         res = self.ldb.search(self.base_dn, scope=SCOPE_BASE,
3017                               attrs=["createTimeStamp", "modifyTimeStamp",
3018                                      "structuralObjectClass", "whenCreated",
3019                                      "whenChanged"])
3020         self.assertEquals(len(res), 1)
3021         self.assertTrue("createTimeStamp" in res[0])
3022         self.assertTrue("modifyTimeStamp" in res[0])
3023         self.assertTrue("structuralObjectClass" in res[0])
3024         self.assertTrue("whenCreated" in res[0])
3025         self.assertTrue("whenChanged" in res[0])
3026
3027 class BaseDnTests(samba.tests.TestCase):
3028
3029     def setUp(self):
3030         super(BaseDnTests, self).setUp()
3031         self.ldb = ldb
3032
3033     def test_rootdse_attrs(self):
3034         """Testing for all rootDSE attributes"""
3035         res = self.ldb.search("", scope=SCOPE_BASE, attrs=[])
3036         self.assertEquals(len(res), 1)
3037
3038     def test_highestcommittedusn(self):
3039         """Testing for highestCommittedUSN"""
3040         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["highestCommittedUSN"])
3041         self.assertEquals(len(res), 1)
3042         self.assertTrue(int(res[0]["highestCommittedUSN"][0]) != 0)
3043
3044     def test_netlogon(self):
3045         """Testing for netlogon via LDAP"""
3046         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["netlogon"])
3047         self.assertEquals(len(res), 0)
3048
3049     def test_netlogon_highestcommitted_usn(self):
3050         """Testing for netlogon and highestCommittedUSN via LDAP"""
3051         res = self.ldb.search("", scope=SCOPE_BASE,
3052                 attrs=["netlogon", "highestCommittedUSN"])
3053         self.assertEquals(len(res), 0)
3054
3055     def test_namingContexts(self):
3056         """Testing for namingContexts in rootDSE"""
3057         res = self.ldb.search("", scope=SCOPE_BASE,
3058                 attrs=["namingContexts", "defaultNamingContext", "schemaNamingContext", "configurationNamingContext"])
3059         self.assertEquals(len(res), 1)
3060
3061         ncs = set([])
3062         for nc in res[0]["namingContexts"]:
3063             self.assertTrue(nc not in ncs)
3064             ncs.add(nc)
3065
3066         self.assertTrue(res[0]["defaultNamingContext"][0] in ncs)
3067         self.assertTrue(res[0]["configurationNamingContext"][0] in ncs)
3068         self.assertTrue(res[0]["schemaNamingContext"][0] in ncs)
3069
3070     def test_serverPath(self):
3071         """Testing the server paths in rootDSE"""
3072         res = self.ldb.search("", scope=SCOPE_BASE,
3073                               attrs=["dsServiceName", "serverName"])
3074         self.assertEquals(len(res), 1)
3075
3076         self.assertTrue("CN=Servers" in res[0]["dsServiceName"][0])
3077         self.assertTrue("CN=Sites" in res[0]["dsServiceName"][0])
3078         self.assertTrue("CN=NTDS Settings" in res[0]["dsServiceName"][0])
3079         self.assertTrue("CN=Servers" in res[0]["serverName"][0])
3080         self.assertTrue("CN=Sites" in res[0]["serverName"][0])
3081         self.assertFalse("CN=NTDS Settings" in res[0]["serverName"][0])
3082
3083     def test_functionality(self):
3084         """Testing the server paths in rootDSE"""
3085         res = self.ldb.search("", scope=SCOPE_BASE,
3086                               attrs=["forestFunctionality", "domainFunctionality", "domainControllerFunctionality"])
3087         self.assertEquals(len(res), 1)
3088         self.assertEquals(len(res[0]["forestFunctionality"]), 1)
3089         self.assertEquals(len(res[0]["domainFunctionality"]), 1)
3090         self.assertEquals(len(res[0]["domainControllerFunctionality"]), 1)
3091
3092         self.assertTrue(int(res[0]["forestFunctionality"][0]) <= int(res[0]["domainFunctionality"][0]))
3093         self.assertTrue(int(res[0]["domainControllerFunctionality"][0]) >= int(res[0]["domainFunctionality"][0]))
3094
3095         res2 = self.ldb.search("", scope=SCOPE_BASE,
3096                               attrs=["dsServiceName", "serverName"])
3097         self.assertEquals(len(res2), 1)
3098         self.assertEquals(len(res2[0]["dsServiceName"]), 1)
3099
3100         res3 = self.ldb.search(res2[0]["dsServiceName"][0], scope=SCOPE_BASE, attrs=["msDS-Behavior-Version"])
3101         self.assertEquals(len(res3), 1)
3102         self.assertEquals(len(res3[0]["msDS-Behavior-Version"]), 1)
3103         self.assertEquals(int(res[0]["domainControllerFunctionality"][0]), int(res3[0]["msDS-Behavior-Version"][0]))
3104
3105         res4 = self.ldb.search(ldb.domain_dn(), scope=SCOPE_BASE, attrs=["msDS-Behavior-Version"])
3106         self.assertEquals(len(res4), 1)
3107         self.assertEquals(len(res4[0]["msDS-Behavior-Version"]), 1)
3108         self.assertEquals(int(res[0]["domainFunctionality"][0]), int(res4[0]["msDS-Behavior-Version"][0]))
3109
3110         res5 = self.ldb.search("cn=partitions,%s" % ldb.get_config_basedn(), scope=SCOPE_BASE, attrs=["msDS-Behavior-Version"])
3111         self.assertEquals(len(res5), 1)
3112         self.assertEquals(len(res5[0]["msDS-Behavior-Version"]), 1)
3113         self.assertEquals(int(res[0]["forestFunctionality"][0]), int(res5[0]["msDS-Behavior-Version"][0]))
3114
3115     def test_dnsHostname(self):
3116         """Testing the DNS hostname in rootDSE"""
3117         res = self.ldb.search("", scope=SCOPE_BASE,
3118                               attrs=["dnsHostName", "serverName"])
3119         self.assertEquals(len(res), 1)
3120
3121         res2 = self.ldb.search(res[0]["serverName"][0], scope=SCOPE_BASE,
3122                                attrs=["dNSHostName"])
3123         self.assertEquals(len(res2), 1)
3124
3125         self.assertEquals(res[0]["dnsHostName"][0], res2[0]["dNSHostName"][0])
3126
3127     def test_ldapServiceName(self):
3128         """Testing the ldap service name in rootDSE"""
3129         res = self.ldb.search("", scope=SCOPE_BASE,
3130                               attrs=["ldapServiceName", "dnsHostName"])
3131         self.assertEquals(len(res), 1)
3132         self.assertTrue("ldapServiceName" in res[0])
3133         self.assertTrue("dnsHostName" in res[0])
3134
3135         (hostname, _, dns_domainname) = res[0]["dnsHostName"][0].partition(".")
3136
3137         given = res[0]["ldapServiceName"][0]
3138         expected = "%s:%s$@%s" % (dns_domainname.lower(), hostname.lower(), dns_domainname.upper())
3139         self.assertEquals(given, expected)
3140
3141 if not "://" in host:
3142     if os.path.isfile(host):
3143         host = "tdb://%s" % host
3144     else:
3145         host = "ldap://%s" % host
3146
3147 ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
3148 if not "tdb://" in host:
3149     gc_ldb = Ldb("%s:3268" % host, credentials=creds,
3150                  session_info=system_session(lp), lp=lp)
3151 else:
3152     gc_ldb = None
3153
3154 runner = SubunitTestRunner()
3155 rc = 0
3156 if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful():
3157     rc = 1
3158 if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful():
3159     rc = 1
3160 sys.exit(rc)