s4:ldap.py - enhance schema addition test
[ira/wip.git] / source4 / lib / ldb / tests / python / ldap.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
4
5 import getopt
6 import optparse
7 import sys
8 import time
9 import random
10 import base64
11
12 sys.path.append("bin/python")
13 sys.path.append("../lib/subunit/python")
14
15 import samba.getopt as options
16
17 from samba.auth import system_session
18 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
19 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
20 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
21 from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX
22 from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INSUFFICIENT_ACCESS_RIGHTS
23 from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN
24 from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
25 from ldb import Message, MessageElement, Dn
26 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
27 from samba import Ldb, param, dom_sid_to_rid
28 from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT
29 from samba import UF_SERVER_TRUST_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT
30 from samba import UF_INTERDOMAIN_TRUST_ACCOUNT
31 from samba import UF_PASSWD_NOTREQD, UF_ACCOUNTDISABLE
32 from samba import GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
33 from samba import GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
34 from samba import GTYPE_SECURITY_UNIVERSAL_GROUP
35 from samba import GTYPE_DISTRIBUTION_GLOBAL_GROUP
36 from samba import GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP
37 from samba import GTYPE_DISTRIBUTION_UNIVERSAL_GROUP
38 from samba import ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST
39 from samba import ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP
40 from samba import ATYPE_SECURITY_UNIVERSAL_GROUP
41 from samba import ATYPE_DISTRIBUTION_GLOBAL_GROUP
42 from samba import ATYPE_DISTRIBUTION_LOCAL_GROUP
43 from samba import ATYPE_DISTRIBUTION_UNIVERSAL_GROUP
44
45 from subunit import SubunitTestRunner
46 import unittest
47
48 from samba.ndr import ndr_pack, ndr_unpack
49 from samba.dcerpc import security
50
51 parser = optparse.OptionParser("ldap [options] <host>")
52 sambaopts = options.SambaOptions(parser)
53 parser.add_option_group(sambaopts)
54 parser.add_option_group(options.VersionOptions(parser))
55 # use command line creds if available
56 credopts = options.CredentialsOptions(parser)
57 parser.add_option_group(credopts)
58 opts, args = parser.parse_args()
59
60 if len(args) < 1:
61     parser.print_usage()
62     sys.exit(1)
63
64 host = args[0]
65
66 lp = sambaopts.get_loadparm()
67 creds = credopts.get_credentials(lp)
68
69 class BasicTests(unittest.TestCase):
70     def delete_force(self, ldb, dn):
71         try:
72             ldb.delete(dn)
73         except LdbError, (num, _):
74             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
75
76     def find_basedn(self, ldb):
77         res = ldb.search(base="", expression="", scope=SCOPE_BASE,
78                          attrs=["defaultNamingContext"])
79         self.assertEquals(len(res), 1)
80         return res[0]["defaultNamingContext"][0]
81
82     def find_configurationdn(self, ldb):
83         res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["configurationNamingContext"])
84         self.assertEquals(len(res), 1)
85         return res[0]["configurationNamingContext"][0]
86
87     def find_schemadn(self, ldb):
88         res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
89         self.assertEquals(len(res), 1)
90         return res[0]["schemaNamingContext"][0]
91
92     def find_domain_sid(self):
93         res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
94         return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
95
96     def setUp(self):
97         self.ldb = ldb
98         self.gc_ldb = gc_ldb
99         self.base_dn = self.find_basedn(ldb)
100         self.configuration_dn = self.find_configurationdn(ldb)
101         self.schema_dn = self.find_schemadn(ldb)
102         self.domain_sid = self.find_domain_sid()
103
104         print "baseDN: %s\n" % self.base_dn
105
106         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
107         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
108         self.delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
109         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
110         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
111         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
112         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
113         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
114         self.delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
115         self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
116         self.delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
117         self.delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
118         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
119         self.delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
120         self.delete_force(self.ldb, "cn=parentguidtest,cn=users," + self.base_dn)
121         self.delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
122         self.delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
123         self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
124         self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
125         self.delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn)
126
127     def test_system_only(self):
128         """Test systemOnly objects"""
129         print "Test systemOnly objects"""
130
131         try:
132             self.ldb.add({
133                 "dn": "cn=ldaptestobject," + self.base_dn,
134                 "objectclass": "configuration"})
135             self.fail()
136         except LdbError, (num, _):
137             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
138
139         self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
140
141     def test_invalid_parent(self):
142         """Test adding an object with invalid parent"""
143         print "Test adding an object with invalid parent"""
144
145         try:
146             self.ldb.add({
147                 "dn": "cn=ldaptestgroup,cn=thisdoesnotexist123,"
148                    + self.base_dn,
149                 "objectclass": "group"})
150             self.fail()
151         except LdbError, (num, _):
152             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
153
154         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=thisdoesnotexist123,"
155           + self.base_dn)
156
157         try:
158             self.ldb.add({
159                 "dn": "ou=testou,cn=users," + self.base_dn,
160                 "objectclass": "organizationalUnit"})
161             self.fail()
162         except LdbError, (num, _):
163             self.assertEquals(num, ERR_NAMING_VIOLATION)
164
165         self.delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn)
166
167     def test_invalid_attribute(self):
168         """Test adding invalid attributes (not in schema)"""
169         print "Test adding invalid attributes (not in schema)"""
170
171         try:
172             self.ldb.add({
173                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
174                 "objectclass": "group",
175                 "thisdoesnotexist": "x"})
176             self.fail()
177         except LdbError, (num, _):
178             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
179
180         self.ldb.add({
181              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
182              "objectclass": "group"})
183
184         m = Message()
185         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
186         m["thisdoesnotexist"] = MessageElement("x", FLAG_MOD_REPLACE,
187           "thisdoesnotexist")
188         try:
189             ldb.modify(m)
190             self.fail()
191         except LdbError, (num, _):
192             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
193
194         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
195
196     def test_single_valued_attributes(self):
197         """Test single-valued attributes"""
198         print "Test single-valued attributes"""
199
200         try:
201             self.ldb.add({
202                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
203                 "objectclass": "group",
204                 "sAMAccountName": ["nam1", "nam2"]})
205             self.fail()
206         except LdbError, (num, _):
207             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
208
209         self.ldb.add({
210              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
211              "objectclass": "group"})
212
213         m = Message()
214         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
215         m["sAMAccountName"] = MessageElement(["nam1","nam2"], FLAG_MOD_REPLACE,
216           "sAMAccountName")
217         try:
218             ldb.modify(m)
219             self.fail()
220         except LdbError, (num, _):
221             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
222
223         m = Message()
224         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
225         m["sAMAccountName"] = MessageElement("testgroupXX", FLAG_MOD_REPLACE,
226           "sAMAccountName")
227         ldb.modify(m)
228
229         m = Message()
230         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
231         m["sAMAccountName"] = MessageElement("testgroupXX2", FLAG_MOD_ADD,
232           "sAMAccountName")
233         try:
234             ldb.modify(m)
235             self.fail()
236         except LdbError, (num, _):
237             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
238
239         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
240
241     def test_multi_valued_attributes(self):
242         """Test multi-valued attributes"""
243         print "Test multi-valued attributes"""
244
245 # TODO: In this test I added some special tests where I got very unusual
246 # results back from a real AD. s4 doesn't match them and I've no idea how to
247 # implement those error cases (maybe there exists a special trigger for
248 # "description" attributes which handle them)
249
250         self.ldb.add({
251             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
252             "description": "desc2",
253             "objectclass": "group",
254             "description": "desc1"})
255
256         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
257
258         self.ldb.add({
259             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
260             "objectclass": "group",
261             "description": ["desc1", "desc2"]})
262
263 #        m = Message()
264 #        m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
265 #        m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
266 #          "description")
267 #        try:
268 #            ldb.modify(m)
269 #            self.fail()
270 #        except LdbError, (num, _):
271 #            self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
272
273         m = Message()
274         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
275         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
276           "description")
277         ldb.modify(m)
278
279 #        m = Message()
280 #        m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
281 #        m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
282 #          "description")
283 #        try:
284 #            ldb.modify(m)
285 #            self.fail()
286 #        except LdbError, (num, _):
287 #            self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
288
289         m = Message()
290         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
291         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
292           "description")
293         try:
294             ldb.modify(m)
295             self.fail()
296         except LdbError, (num, _):
297             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
298
299         m = Message()
300         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
301         m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
302           "description")
303         ldb.modify(m)
304
305 #        m = Message()
306 #        m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
307 #        m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
308 #          "description")
309 #        try:
310 #            ldb.modify(m)
311 #            self.fail()
312 #        except LdbError, (num, _):
313 #            self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
314
315 #        m = Message()
316 #        m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
317 #        m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
318 #          "description")
319 #        try:
320 #            ldb.modify(m)
321 #            self.fail()
322 #        except LdbError, (num, _):
323 #            self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
324
325         m = Message()
326         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
327         m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
328           "description")
329         ldb.modify(m)
330
331         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
332
333     def test_empty_messages(self):
334         """Test empty messages"""
335         print "Test empty messages"""
336
337         m = Message()
338         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
339
340         try:
341             ldb.add(m)
342             self.fail()
343         except LdbError, (num, _):
344             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
345
346         try:
347             ldb.modify(m)
348             self.fail()
349         except LdbError, (num, _):
350             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
351
352         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
353
354     def test_empty_attributes(self):
355         """Test empty attributes"""
356         print "Test empty attributes"""
357
358         m = Message()
359         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
360         m["objectClass"] = MessageElement("group", FLAG_MOD_ADD, "objectClass")
361         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
362
363         try:
364             ldb.add(m)
365             self.fail()
366         except LdbError, (num, _):
367             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
368
369         self.ldb.add({
370             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
371             "objectclass": "group"})
372
373         m = Message()
374         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
375         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
376
377         try:
378             ldb.modify(m)
379             self.fail()
380         except LdbError, (num, _):
381             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
382
383         m = Message()
384         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
385         m["description"] = MessageElement([], FLAG_MOD_REPLACE, "description")
386         ldb.modify(m)
387
388         m = Message()
389         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
390         m["description"] = MessageElement([], FLAG_MOD_DELETE, "description")
391         try:
392             ldb.modify(m)
393             self.fail()
394         except LdbError, (num, _):
395             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
396
397         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
398
399     def test_distinguished_name(self):
400         """Tests the 'distinguishedName' attribute"""
401         print "Tests the 'distinguishedName' attribute"""
402
403         self.ldb.add({
404              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
405              "objectclass": "group"})
406
407         m = Message()
408         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
409         m["distinguishedName"] = MessageElement(
410           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_ADD,
411           "distinguishedName")
412
413         try:
414             ldb.modify(m)
415             self.fail()
416         except LdbError, (num, _):
417             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
418
419         m = Message()
420         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
421         m["distinguishedName"] = MessageElement(
422           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
423           "distinguishedName")
424
425         try:
426             ldb.modify(m)
427             self.fail()
428         except LdbError, (num, _):
429             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
430
431         m = Message()
432         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
433         m["distinguishedName"] = MessageElement(
434           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_DELETE,
435           "distinguishedName")
436
437         try:
438             ldb.modify(m)
439             self.fail()
440         except LdbError, (num, _):
441             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
442
443         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
444
445     def test_rdn_name(self):
446         """Tests the RDN"""
447         print "Tests the RDN"""
448
449         try:
450             self.ldb.add({
451                  "dn": "description=xyz,cn=users," + self.base_dn,
452                  "objectclass": "group"})
453             self.fail()
454         except LdbError, (num, _):
455             self.assertEquals(num, ERR_NAMING_VIOLATION)
456  
457         self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
458
459         self.ldb.add({
460              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
461              "objectclass": "group"})
462
463         m = Message()
464         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
465         m["name"] = MessageElement("cn=ldaptestuser", FLAG_MOD_REPLACE,
466           "name")
467
468         try:
469             ldb.modify(m)
470             self.fail()
471         except LdbError, (num, _):
472             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
473
474         m = Message()
475         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
476         m["cn"] = MessageElement("ldaptestuser",
477           FLAG_MOD_REPLACE, "cn")
478
479         try:
480             ldb.modify(m)
481             self.fail()
482         except LdbError, (num, _):
483             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
484
485         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
486
487
488         # this test needs to be disabled until we really understand
489         # what the rDN length constraints are
490     def DISABLED_test_largeRDN(self):
491         """Testing large rDN (limit 64 characters)"""
492         rdn = "CN=a012345678901234567890123456789012345678901234567890123456789012";
493         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
494         ldif = """
495 dn: %s,%s""" % (rdn,self.base_dn) + """
496 objectClass: container
497 """
498         self.ldb.add_ldif(ldif)
499         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
500
501         rdn = "CN=a0123456789012345678901234567890123456789012345678901234567890120";
502         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
503         try:
504             ldif = """
505 dn: %s,%s""" % (rdn,self.base_dn) + """
506 objectClass: container
507 """
508             self.ldb.add_ldif(ldif)
509             self.fail()
510         except LdbError, (num, _):
511             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
512         self.delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
513
514     def test_rename(self):
515         """Tests the rename operation"""
516         print "Tests the rename operations"""
517
518         self.ldb.add({
519              "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
520              "objectclass": ["user", "person"] })
521
522         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
523         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
524         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestUSER3,cn=users," + self.base_dn)
525         try:
526             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, ",cn=users," + self.base_dn)
527             self.fail()
528         except LdbError, (num, _):
529             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
530
531         self.delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
532
533     def test_parentGUID(self):
534         """Test parentGUID behaviour"""
535         print "Testing parentGUID behaviour\n"
536
537         # TODO: This seems to fail on Windows Server. Hidden attribute?
538
539         self.ldb.add({
540             "dn": "cn=parentguidtest,cn=users," + self.base_dn,
541             "objectclass":"user",
542             "samaccountname":"parentguidtest"});
543         res1 = ldb.search(base="cn=parentguidtest,cn=users," + self.base_dn, scope=SCOPE_BASE,
544                           attrs=["parentGUID"]);
545         res2 = ldb.search(base="cn=users," + self.base_dn,scope=SCOPE_BASE,
546                           attrs=["objectGUID"]);
547         self.assertEquals(res1[0]["parentGUID"], res2[0]["objectGUID"]);
548
549         print "Testing parentGUID behaviour on rename\n"
550
551         self.ldb.add({
552             "dn": "cn=testotherusers," + self.base_dn,
553             "objectclass":"container"});
554         res1 = ldb.search(base="cn=testotherusers," + self.base_dn,scope=SCOPE_BASE,
555                           attrs=["objectGUID"]);
556         ldb.rename("cn=parentguidtest,cn=users," + self.base_dn,
557                    "cn=parentguidtest,cn=testotherusers," + self.base_dn);
558         res2 = ldb.search(base="cn=parentguidtest,cn=testotherusers," + self.base_dn,
559                           scope=SCOPE_BASE,
560                           attrs=["parentGUID"]);
561         self.assertEquals(res1[0]["objectGUID"], res2[0]["parentGUID"]);
562
563         self.delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
564         self.delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
565
566     def test_groupType_int32(self):
567         """Test groupType (int32) behaviour (should appear to be casted to a 32 bit signed integer before comparsion)"""
568         print "Testing groupType (int32) behaviour\n"
569
570         res1 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
571                           attrs=["groupType"], expression="groupType=2147483653");
572
573         res2 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
574                           attrs=["groupType"], expression="groupType=-2147483643");
575
576         self.assertEquals(len(res1), len(res2))
577
578         self.assertTrue(res1.count > 0)
579
580         self.assertEquals(res1[0]["groupType"][0], "-2147483643")
581
582     def test_groups(self):
583         """This tests the group behaviour (setting, changing) of a user account"""
584         print "Testing group behaviour\n"
585
586         ldb.add({
587             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
588             "objectclass": "group"})
589
590         ldb.add({
591             "dn": "cn=ldaptestgroup2,cn=users," + self.base_dn,
592             "objectclass": "group"})
593
594         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
595                           scope=SCOPE_BASE, attrs=["objectSID"])
596         self.assertTrue(len(res1) == 1)
597         group_rid_1 = dom_sid_to_rid(ldb.schema_format_value("objectSID",
598           res1[0]["objectSID"][0]))
599
600         res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
601                           scope=SCOPE_BASE, attrs=["objectSID"])
602         self.assertTrue(len(res1) == 1)
603         group_rid_2 = dom_sid_to_rid(ldb.schema_format_value("objectSID",
604           res1[0]["objectSID"][0]))
605
606         # Try to create a user with an invalid primary group
607         try:
608             ldb.add({
609                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
610                 "objectclass": ["user", "person"],
611                 "primaryGroupID": "0"})
612             self.fail()
613         except LdbError, (num, _):
614             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
615         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
616
617         # Try to Create a user with a valid primary group
618 # TODO Some more investigation needed here
619 #        try:
620 #            ldb.add({
621 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
622 #                "objectclass": ["user", "person"],
623 #                "primaryGroupID": str(group_rid_1)})
624 #            self.fail()
625 #        except LdbError, (num, _):
626 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
627 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
628
629         ldb.add({
630             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
631             "objectclass": ["user", "person"]})
632
633         # Try to add invalid primary group
634         m = Message()
635         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
636         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
637           "primaryGroupID")
638         try:
639             ldb.modify(m)
640             self.fail()
641         except LdbError, (num, _):
642             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
643
644         # Try to make group 1 primary - should be denied since it is not yet
645         # secondary
646         m = Message()
647         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
648         m["primaryGroupID"] = MessageElement(str(group_rid_1),
649           FLAG_MOD_REPLACE, "primaryGroupID")
650         try:
651             ldb.modify(m)
652             self.fail()
653         except LdbError, (num, _):
654             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
655
656         # Make group 1 secondary
657         m = Message()
658         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
659         m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn
660         ldb.modify(m)
661
662         # Make group 1 primary
663         m = Message()
664         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
665         m["primaryGroupID"] = MessageElement(str(group_rid_1),
666           FLAG_MOD_REPLACE, "primaryGroupID")
667         ldb.modify(m)
668
669         # Try to delete group 1 - should be denied
670         try:
671             ldb.delete("cn=ldaptestgroup,cn=users," + self.base_dn)
672             self.fail()
673         except LdbError, (num, _):
674             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
675
676         # Try to add group 1 also as secondary - should be denied
677         m = Message()
678         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
679         m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn
680         try:
681             ldb.modify(m)
682             self.fail()
683         except LdbError, (num, _):
684             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
685
686         # Try to add invalid member to group 1 - should be denied
687         m = Message()
688         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
689         m["member"] = MessageElement(
690           "cn=ldaptestuser3,cn=users," + self.base_dn,
691           FLAG_MOD_ADD, "member")
692         try:
693             ldb.modify(m)
694             self.fail()
695         except LdbError, (num, _):
696             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
697
698         # Make group 2 secondary
699         m = Message()
700         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
701         m["member"] = "cn=ldaptestuser,cn=users," + self.base_dn
702         ldb.modify(m)
703
704         # Swap the groups
705         m = Message()
706         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
707         m["primaryGroupID"] = MessageElement(str(group_rid_2),
708           FLAG_MOD_REPLACE, "primaryGroupID")
709         ldb.modify(m)
710
711         # Old primary group should contain a "member" attribute for the user,
712         # the new shouldn't contain anymore one
713         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
714                           scope=SCOPE_BASE, attrs=["member"])
715         self.assertTrue(len(res1) == 1)
716         self.assertTrue(len(res1[0]["member"]) == 1)
717         self.assertEquals(res1[0]["member"][0].lower(),
718           ("cn=ldaptestuser,cn=users," + self.base_dn).lower())
719
720         res1 = ldb.search("cn=ldaptestgroup2, cn=users," + self.base_dn,
721                           scope=SCOPE_BASE, attrs=["member"])
722         self.assertTrue(len(res1) == 1)
723         self.assertFalse("member" in res1[0])
724
725         # Also this should be denied
726         try:
727             ldb.add({
728               "dn": "cn=ldaptestuser1,cn=users," + self.base_dn,
729               "objectclass": ["user", "person"],
730               "primaryGroupID": "0"})
731             self.fail()
732         except LdbError, (num, _):
733             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
734
735         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
736         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
737         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
738
739     def test_primary_group_token(self):
740         """Test the primary group token behaviour (hidden-generated-readonly attribute on groups)"""
741         print "Testing primary group token behaviour\n"
742
743         ldb.add({
744             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
745             "objectclass": ["user", "person"]})
746
747         ldb.add({
748             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
749             "objectclass": "group"})
750
751         res1 = ldb.search("cn=ldaptestuser, cn=users," + self.base_dn,
752                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
753         self.assertTrue(len(res1) == 1)
754         self.assertFalse("primaryGroupToken" in res1[0])
755
756         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
757                           scope=SCOPE_BASE)
758         self.assertTrue(len(res1) == 1)
759         self.assertFalse("primaryGroupToken" in res1[0])
760
761         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
762                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "objectSID"])
763         self.assertTrue(len(res1) == 1)
764         primary_group_token = int(res1[0]["primaryGroupToken"][0])
765
766         rid = dom_sid_to_rid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0]))
767         self.assertEquals(primary_group_token, rid)
768
769 # TODO Has to wait until we support read-only generated attributes correctly
770 #        m = Message()
771 #        m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
772 #        m["primaryGroupToken"] = "100"
773 #        try:
774 #                ldb.modify(m)
775 #                self.fail()
776 #        except LdbError, (num, msg):
777
778         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
779         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
780
781     def test_wkguid(self):
782         """Test Well known GUID behaviours (including DN+Binary)"""
783         print "Test Well known GUID behaviours (including DN+Binary)"""
784
785         res = self.ldb.search(base=("<WKGUID=ab1d30f3768811d1aded00c04fd8d5cd,%s>" % self.base_dn), scope=SCOPE_BASE, attrs=[])
786         self.assertEquals(len(res), 1)
787         
788         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd:%s" % res[0].dn))
789         self.assertEquals(len(res2), 1)
790
791         # Prove that the matching rule is over the whole DN+Binary
792         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd"))
793         self.assertEquals(len(res2), 0)
794         # Prove that the matching rule is over the whole DN+Binary
795         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=%s") % res[0].dn)
796         self.assertEquals(len(res2), 0)
797
798     def test_all(self):
799         """Basic tests"""
800
801         print "Testing user add"
802
803         ldb.add({
804             "dn": "cn=ldaptestuser,cn=uSers," + self.base_dn,
805             "objectclass": ["user", "person"],
806             "cN": "LDAPtestUSER",
807             "givenname": "ldap",
808             "sn": "testy"})
809
810         ldb.add({
811             "dn": "cn=ldaptestgroup,cn=uSers," + self.base_dn,
812             "objectclass": "group",
813             "member": "cn=ldaptestuser,cn=useRs," + self.base_dn})
814
815         ldb.add({
816             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
817             "objectclass": "computer",
818             "cN": "LDAPtestCOMPUTER"})
819
820         ldb.add({"dn": "cn=ldaptest2computer,cn=computers," + self.base_dn,
821             "objectClass": "computer",
822             "cn": "LDAPtest2COMPUTER",
823             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT),
824             "displayname": "ldap testy"})
825
826         try:
827             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
828                      "objectClass": "computer",
829                      "cn": "LDAPtest2COMPUTER"
830                      })
831             self.fail()
832         except LdbError, (num, _):
833             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
834
835         try:
836             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
837                      "objectClass": "computer",
838                      "cn": "ldaptestcomputer3",
839                      "sAMAccountType": str(ATYPE_NORMAL_ACCOUNT)
840                 })
841             self.fail()
842         except LdbError, (num, _):
843             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
844
845         ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
846                  "objectClass": "computer",
847                  "cn": "LDAPtestCOMPUTER3"
848                  })
849
850         print "Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))";
851         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestcomputer3)(objectClass=user))");
852         self.assertEquals(len(res), 1, "Found only %d for (&(cn=ldaptestcomputer3)(objectClass=user))" % len(res))
853
854         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer3,CN=Computers," + self.base_dn));
855         self.assertEquals(res[0]["cn"][0], "ldaptestcomputer3");
856         self.assertEquals(res[0]["name"][0], "ldaptestcomputer3");
857         self.assertEquals(res[0]["objectClass"][0], "top");
858         self.assertEquals(res[0]["objectClass"][1], "person");
859         self.assertEquals(res[0]["objectClass"][2], "organizationalPerson");
860         self.assertEquals(res[0]["objectClass"][3], "user");
861         self.assertEquals(res[0]["objectClass"][4], "computer");
862         self.assertTrue("objectGUID" in res[0])
863         self.assertTrue("whenCreated" in res[0])
864         self.assertEquals(res[0]["objectCategory"][0], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn));
865         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513);
866         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT);
867         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE);
868
869         self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
870
871         print "Testing attribute or value exists behaviour"
872         try:
873             ldb.modify_ldif("""
874 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
875 changetype: modify
876 replace: servicePrincipalName
877 servicePrincipalName: host/ldaptest2computer
878 servicePrincipalName: host/ldaptest2computer
879 servicePrincipalName: cifs/ldaptest2computer
880 """)
881             self.fail()
882         except LdbError, (num, msg):
883             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
884
885         ldb.modify_ldif("""
886 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
887 changetype: modify
888 replace: servicePrincipalName
889 servicePrincipalName: host/ldaptest2computer
890 servicePrincipalName: cifs/ldaptest2computer
891 """)
892         try:
893             ldb.modify_ldif("""
894 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
895 changetype: modify
896 add: servicePrincipalName
897 servicePrincipalName: host/ldaptest2computer
898 """)
899             self.fail()
900         except LdbError, (num, msg):
901             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
902
903         print "Testing ranged results"
904         ldb.modify_ldif("""
905 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
906 changetype: modify
907 replace: servicePrincipalName
908 """)
909
910         ldb.modify_ldif("""
911 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
912 changetype: modify
913 add: servicePrincipalName
914 servicePrincipalName: host/ldaptest2computer0
915 servicePrincipalName: host/ldaptest2computer1
916 servicePrincipalName: host/ldaptest2computer2
917 servicePrincipalName: host/ldaptest2computer3
918 servicePrincipalName: host/ldaptest2computer4
919 servicePrincipalName: host/ldaptest2computer5
920 servicePrincipalName: host/ldaptest2computer6
921 servicePrincipalName: host/ldaptest2computer7
922 servicePrincipalName: host/ldaptest2computer8
923 servicePrincipalName: host/ldaptest2computer9
924 servicePrincipalName: host/ldaptest2computer10
925 servicePrincipalName: host/ldaptest2computer11
926 servicePrincipalName: host/ldaptest2computer12
927 servicePrincipalName: host/ldaptest2computer13
928 servicePrincipalName: host/ldaptest2computer14
929 servicePrincipalName: host/ldaptest2computer15
930 servicePrincipalName: host/ldaptest2computer16
931 servicePrincipalName: host/ldaptest2computer17
932 servicePrincipalName: host/ldaptest2computer18
933 servicePrincipalName: host/ldaptest2computer19
934 servicePrincipalName: host/ldaptest2computer20
935 servicePrincipalName: host/ldaptest2computer21
936 servicePrincipalName: host/ldaptest2computer22
937 servicePrincipalName: host/ldaptest2computer23
938 servicePrincipalName: host/ldaptest2computer24
939 servicePrincipalName: host/ldaptest2computer25
940 servicePrincipalName: host/ldaptest2computer26
941 servicePrincipalName: host/ldaptest2computer27
942 servicePrincipalName: host/ldaptest2computer28
943 servicePrincipalName: host/ldaptest2computer29
944 """)
945
946         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE,
947                          attrs=["servicePrincipalName;range=0-*"])
948         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
949         #print len(res[0]["servicePrincipalName;range=0-*"])
950         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
951
952         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
953         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
954             # print res[0]["servicePrincipalName;range=0-19"].length
955         self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
956
957
958         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
959         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
960         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
961
962         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
963         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
964         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
965
966         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
967         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
968         self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
969
970
971         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
972         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
973         self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
974         # pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
975
976         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
977         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
978         self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
979             # print res[0]["servicePrincipalName;range=11-*"][18]
980             # print pos_11
981             # self.assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11)
982
983         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
984         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
985         self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
986             # self.assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11)
987
988         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
989         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
990             # print res[0]["servicePrincipalName"][18]
991             # print pos_11
992         self.assertEquals(len(res[0]["servicePrincipalName"]), 30)
993             # self.assertEquals(res[0]["servicePrincipalName"][18], pos_11)
994
995         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
996         ldb.add({
997             "dn": "cn=ldaptestuser2,cn=useRs," + self.base_dn,
998             "objectClass": ["person", "user"],
999             "cn": "LDAPtestUSER2",
1000             "givenname": "testy",
1001             "sn": "ldap user2"})
1002
1003         print "Testing Ambigious Name Resolution"
1004         # Testing ldb.search for (&(anr=ldap testy)(objectClass=user))
1005         res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))")
1006         self.assertEquals(len(res), 3, "Found only %d of 3 for (&(anr=ldap testy)(objectClass=user))" % len(res))
1007
1008         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
1009         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
1010         self.assertEquals(len(res), 2, "Found only %d of 2 for (&(anr=testy ldap)(objectClass=user))" % len(res))
1011
1012         # Testing ldb.search for (&(anr=ldap)(objectClass=user))
1013         res = ldb.search(expression="(&(anr=ldap)(objectClass=user))")
1014         self.assertEquals(len(res), 4, "Found only %d of 4 for (&(anr=ldap)(objectClass=user))" % len(res))
1015
1016         # Testing ldb.search for (&(anr==ldap)(objectClass=user))
1017         res = ldb.search(expression="(&(anr==ldap)(objectClass=user))")
1018         self.assertEquals(len(res), 1, "Could not find (&(anr==ldap)(objectClass=user)). Found only %d for (&(anr=ldap)(objectClass=user))" % len(res))
1019
1020         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1021         self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1022         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
1023
1024         # Testing ldb.search for (&(anr=testy)(objectClass=user))
1025         res = ldb.search(expression="(&(anr=testy)(objectClass=user))")
1026         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res))
1027
1028         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
1029         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
1030         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res))
1031
1032         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
1033 # this test disabled for the moment, as anr with == tests are not understood
1034 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
1035 #        self.assertEquals(len(res), 1, "Found only %d for (&(anr==testy ldap)(objectClass=user))" % len(res))
1036
1037 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1038 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1039 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
1040
1041         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
1042 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
1043 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap)(objectClass=user))")
1044
1045 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1046 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1047 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
1048
1049         # Testing ldb.search for (&(anr=testy ldap user)(objectClass=user))
1050         res = ldb.search(expression="(&(anr=testy ldap user)(objectClass=user))")
1051         self.assertEquals(len(res), 1, "Could not find (&(anr=testy ldap user)(objectClass=user))")
1052
1053         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1054         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1055         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1056
1057         # Testing ldb.search for (&(anr==testy ldap user2)(objectClass=user))
1058 #        res = ldb.search(expression="(&(anr==testy ldap user2)(objectClass=user))")
1059 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap user2)(objectClass=user))")
1060
1061         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1062         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1063         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1064
1065         # Testing ldb.search for (&(anr==ldap user2)(objectClass=user))
1066 #        res = ldb.search(expression="(&(anr==ldap user2)(objectClass=user))")
1067 #        self.assertEquals(len(res), 1, "Could not find (&(anr==ldap user2)(objectClass=user))")
1068
1069         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1070         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1071         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1072
1073         # Testing ldb.search for (&(anr==not ldap user2)(objectClass=user))
1074 #        res = ldb.search(expression="(&(anr==not ldap user2)(objectClass=user))")
1075 #        self.assertEquals(len(res), 0, "Must not find (&(anr==not ldap user2)(objectClass=user))")
1076
1077         # Testing ldb.search for (&(anr=not ldap user2)(objectClass=user))
1078         res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))")
1079         self.assertEquals(len(res), 0, "Must not find (&(anr=not ldap user2)(objectClass=user))")
1080
1081         # Testing ldb.search for (&(anr="testy ldap")(objectClass=user)) (ie, with quotes)
1082 #        res = ldb.search(expression="(&(anr==\"testy ldap\")(objectClass=user))")
1083 #        self.assertEquals(len(res), 0, "Found (&(anr==\"testy ldap\")(objectClass=user))")
1084
1085         print "Testing Renames"
1086
1087         attrs = ["objectGUID", "objectSid"]
1088         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
1089         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
1090         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
1091
1092         # Check rename works with extended/alternate DN forms
1093         ldb.rename("<SID=" + ldb.schema_format_value("objectSID", res_user[0]["objectSID"][0]) + ">" , "cn=ldaptestUSER3,cn=users," + self.base_dn)
1094
1095         print "Testing ldb.search for (&(cn=ldaptestuser3)(objectClass=user))"
1096         res = ldb.search(expression="(&(cn=ldaptestuser3)(objectClass=user))")
1097         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser3)(objectClass=user))")
1098
1099         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1100         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1101         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1102
1103         #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"
1104         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
1105         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
1106
1107         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1108         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1109         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1110
1111         #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"
1112         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
1113         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
1114
1115         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1116         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1117         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1118
1119         #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"
1120         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
1121         self.assertEquals(len(res), 0, "(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
1122
1123         # This is a Samba special, and does not exist in real AD
1124         #    print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1125         #    res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1126         #    if (res.error != 0 || len(res) != 1) {
1127         #        print "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1128         #        self.assertEquals(len(res), 1)
1129         #    }
1130         #    self.assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1131         #    self.assertEquals(res[0].cn, "ldaptestUSER3")
1132         #    self.assertEquals(res[0].name, "ldaptestUSER3")
1133
1134         print "Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1135         res = ldb.search(expression="(distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1136         self.assertEquals(len(res), 1, "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1137         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1138         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1139         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1140
1141         # ensure we cannot add it again
1142         try:
1143             ldb.add({"dn": "cn=ldaptestuser3,cn=userS," + self.base_dn,
1144                       "objectClass": ["person", "user"],
1145                       "cn": "LDAPtestUSER3"})
1146             self.fail()
1147         except LdbError, (num, _):
1148             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
1149
1150         # rename back
1151         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1152
1153         # ensure we cannot rename it twice
1154         try:
1155             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn,
1156                        "cn=ldaptestuser2,cn=users," + self.base_dn)
1157             self.fail()
1158         except LdbError, (num, _):
1159             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1160
1161         # ensure can now use that name
1162         ldb.add({"dn": "cn=ldaptestuser3,cn=users," + self.base_dn,
1163                       "objectClass": ["person", "user"],
1164                       "cn": "LDAPtestUSER3"})
1165
1166         # ensure we now cannot rename
1167         try:
1168             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
1169             self.fail()
1170         except LdbError, (num, _):
1171             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
1172         try:
1173             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=configuration," + self.base_dn)
1174             self.fail()
1175         except LdbError, (num, _):
1176             self.assertTrue(num in (71, 64))
1177
1178         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser5,cn=users," + self.base_dn)
1179
1180         ldb.delete("cn=ldaptestuser5,cn=users," + self.base_dn)
1181
1182         self.delete_force(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1183
1184         ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1185
1186         print "Testing subtree renames"
1187
1188         ldb.add({"dn": "cn=ldaptestcontainer," + self.base_dn,
1189                  "objectClass": "container"})
1190
1191         ldb.add({"dn": "CN=ldaptestuser4,CN=ldaptestcontainer," + self.base_dn,
1192                  "objectClass": ["person", "user"],
1193                  "cn": "LDAPtestUSER4"})
1194
1195         ldb.modify_ldif("""
1196 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1197 changetype: modify
1198 add: member
1199 member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
1200 member: cn=ldaptestcomputer,cn=computers,""" + self.base_dn + """
1201 member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """
1202 """)
1203
1204         print "Testing ldb.rename of cn=ldaptestcontainer," + self.base_dn + " to cn=ldaptestcontainer2," + self.base_dn
1205         ldb.rename("CN=ldaptestcontainer," + self.base_dn, "CN=ldaptestcontainer2," + self.base_dn)
1206
1207         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user))"
1208         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))")
1209         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user))")
1210
1211         print "Testing subtree ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
1212         try:
1213             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1214                     expression="(&(cn=ldaptestuser4)(objectClass=user))",
1215                     scope=SCOPE_SUBTREE)
1216             self.fail(res)
1217         except LdbError, (num, _):
1218             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1219
1220         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
1221         try:
1222             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1223                     expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_ONELEVEL)
1224             self.fail()
1225         except LdbError, (num, _):
1226             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1227
1228         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in renamed container"
1229         res = ldb.search("cn=ldaptestcontainer2," + self.base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_SUBTREE)
1230         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user)) under cn=ldaptestcontainer2," + self.base_dn)
1231
1232         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
1233         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1234
1235         time.sleep(4)
1236
1237         print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"
1238         res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE)
1239         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?")
1240
1241         print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn
1242         try:
1243             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn)
1244             self.fail()
1245         except LdbError, (num, _):
1246             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1247
1248         print "Testing ldb.rename (into non-existent container) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn
1249         try:
1250             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn)
1251             self.fail()
1252         except LdbError, (num, _):
1253             self.assertTrue(num in (ERR_UNWILLING_TO_PERFORM, ERR_OTHER))
1254
1255         print "Testing delete (should fail, not a leaf node) of renamed cn=ldaptestcontainer2," + self.base_dn
1256         try:
1257             ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
1258             self.fail()
1259         except LdbError, (num, _):
1260             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
1261
1262         print "Testing base ldb.search for CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn
1263         res = ldb.search(expression="(objectclass=*)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
1264         self.assertEquals(len(res), 1)
1265         res = ldb.search(expression="(cn=ldaptestuser40)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
1266         self.assertEquals(len(res), 0)
1267
1268         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
1269         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_ONELEVEL)
1270         # FIXME: self.assertEquals(len(res), 0)
1271
1272         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
1273         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_SUBTREE)
1274         # FIXME: self.assertEquals(len(res), 0)
1275
1276         print "Testing delete of subtree renamed "+("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn)
1277         ldb.delete(("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
1278         print "Testing delete of renamed cn=ldaptestcontainer2," + self.base_dn
1279         ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
1280
1281         ldb.add({"dn": "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
1282
1283         ldb.add({"dn": "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
1284
1285         print "Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))"
1286         res = ldb.search(expression="(&(cn=ldaptestuser)(objectClass=user))")
1287         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
1288
1289         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1290         self.assertEquals(str(res[0]["cn"]), "ldaptestuser")
1291         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
1292         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user"]))
1293         self.assertTrue("objectGUID" in res[0])
1294         self.assertTrue("whenCreated" in res[0])
1295         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Person,CN=Schema,CN=Configuration," + self.base_dn))
1296         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
1297         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
1298         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1299         self.assertEquals(len(res[0]["memberOf"]), 1)
1300
1301         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))"
1302         res2 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))")
1303         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))")
1304
1305         self.assertEquals(res[0].dn, res2[0].dn)
1306
1307         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon))"
1308         res3 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
1309         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)): matched %d" % len(res3))
1310
1311         self.assertEquals(res[0].dn, res3[0].dn)
1312
1313         if gc_ldb is not None:
1314             print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog"
1315             res3gc = gc_ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
1316             self.assertEquals(len(res3gc), 1)
1317
1318             self.assertEquals(res[0].dn, res3gc[0].dn)
1319
1320         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in with 'phantom root' control"
1321
1322         res3control = gc_ldb.search(self.base_dn, expression="(&(cn=ldaptestuser)(objectCategory=PerSon))", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
1323         self.assertEquals(len(res3control), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog")
1324
1325         self.assertEquals(res[0].dn, res3control[0].dn)
1326
1327         ldb.delete(res[0].dn)
1328
1329         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))"
1330         res = ldb.search(expression="(&(cn=ldaptestcomputer)(objectClass=user))")
1331         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
1332
1333         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer,CN=Computers," + self.base_dn))
1334         self.assertEquals(str(res[0]["cn"]), "ldaptestcomputer")
1335         self.assertEquals(str(res[0]["name"]), "ldaptestcomputer")
1336         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user", "computer"]))
1337         self.assertTrue("objectGUID" in res[0])
1338         self.assertTrue("whenCreated" in res[0])
1339         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn))
1340         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513)
1341         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
1342         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
1343         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1344         self.assertEquals(len(res[0]["memberOf"]), 1)
1345
1346         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))"
1347         res2 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
1348         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
1349
1350         self.assertEquals(res[0].dn, res2[0].dn)
1351
1352         if gc_ldb is not None:
1353             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog"
1354             res2gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
1355             self.assertEquals(len(res2gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog")
1356
1357             self.assertEquals(res[0].dn, res2gc[0].dn)
1358
1359         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER))"
1360         res3 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
1361         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER))")
1362
1363         self.assertEquals(res[0].dn, res3[0].dn)
1364
1365         if gc_ldb is not None:
1366             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog"
1367             res3gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
1368             self.assertEquals(len(res3gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog")
1369
1370             self.assertEquals(res[0].dn, res3gc[0].dn)
1371
1372         print "Testing ldb.search for (&(cn=ldaptestcomp*r)(objectCategory=compuTER))"
1373         res4 = ldb.search(expression="(&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
1374         self.assertEquals(len(res4), 1, "Could not find (&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
1375
1376         self.assertEquals(res[0].dn, res4[0].dn)
1377
1378         print "Testing ldb.search for (&(cn=ldaptestcomput*)(objectCategory=compuTER))"
1379         res5 = ldb.search(expression="(&(cn=ldaptestcomput*)(objectCategory=compuTER))")
1380         self.assertEquals(len(res5), 1, "Could not find (&(cn=ldaptestcomput*)(objectCategory=compuTER))")
1381
1382         self.assertEquals(res[0].dn, res5[0].dn)
1383
1384         print "Testing ldb.search for (&(cn=*daptestcomputer)(objectCategory=compuTER))"
1385         res6 = ldb.search(expression="(&(cn=*daptestcomputer)(objectCategory=compuTER))")
1386         self.assertEquals(len(res6), 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))")
1387
1388         self.assertEquals(res[0].dn, res6[0].dn)
1389
1390         ldb.delete("<GUID=" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + ">")
1391
1392         print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))"
1393         res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))")
1394         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptest2computer)(objectClass=user))")
1395
1396         self.assertEquals(str(res[0].dn), "CN=ldaptest2computer,CN=Computers," + self.base_dn)
1397         self.assertEquals(str(res[0]["cn"]), "ldaptest2computer")
1398         self.assertEquals(str(res[0]["name"]), "ldaptest2computer")
1399         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user", "computer"])
1400         self.assertTrue("objectGUID" in res[0])
1401         self.assertTrue("whenCreated" in res[0])
1402         self.assertEquals(res[0]["objectCategory"][0], "CN=Computer,CN=Schema,CN=Configuration," + self.base_dn)
1403         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST)
1404         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT)
1405
1406         ldb.delete("<SID=" + ldb.schema_format_value("objectSID", res[0]["objectSID"][0]) + ">")
1407
1408         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "memberOf", "allowedAttributes", "allowedAttributesEffective"]
1409         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
1410         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
1411         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
1412
1413         self.assertEquals(str(res_user[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1414         self.assertEquals(str(res_user[0]["cn"]), "ldaptestuser2")
1415         self.assertEquals(str(res_user[0]["name"]), "ldaptestuser2")
1416         self.assertEquals(list(res_user[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
1417         self.assertTrue("objectSid" in res_user[0])
1418         self.assertTrue("objectGUID" in res_user[0])
1419         self.assertTrue("whenCreated" in res_user[0])
1420         self.assertTrue("nTSecurityDescriptor" in res_user[0])
1421         self.assertTrue("allowedAttributes" in res_user[0])
1422         self.assertTrue("allowedAttributesEffective" in res_user[0])
1423         self.assertEquals(res_user[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1424
1425         ldaptestuser2_sid = res_user[0]["objectSid"][0]
1426         ldaptestuser2_guid = res_user[0]["objectGUID"][0]
1427
1428         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "member", "allowedAttributes", "allowedAttributesEffective"]
1429         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))"
1430         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
1431         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
1432
1433         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
1434         self.assertEquals(str(res[0]["cn"]), "ldaptestgroup2")
1435         self.assertEquals(str(res[0]["name"]), "ldaptestgroup2")
1436         self.assertEquals(list(res[0]["objectClass"]), ["top", "group"])
1437         self.assertTrue("objectGUID" in res[0])
1438         self.assertTrue("objectSid" in res[0])
1439         self.assertTrue("whenCreated" in res[0])
1440         self.assertTrue("nTSecurityDescriptor" in res[0])
1441         self.assertTrue("allowedAttributes" in res[0])
1442         self.assertTrue("allowedAttributesEffective" in res[0])
1443         memberUP = []
1444         for m in res[0]["member"]:
1445             memberUP.append(m.upper())
1446         self.assertTrue(("CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
1447
1448         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs, controls=["extended_dn:1:1"])
1449         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
1450
1451         print res[0]["member"]
1452         memberUP = []
1453         for m in res[0]["member"]:
1454             memberUP.append(m.upper())
1455         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()
1456
1457         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)
1458
1459         print "Testing Linked attribute behaviours"
1460         ldb.modify_ldif("""
1461 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1462 changetype: modify
1463 replace: member
1464 member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
1465 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
1466 """)
1467
1468         ldb.modify_ldif("""
1469 dn: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
1470 changetype: modify
1471 replace: member
1472 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
1473 """)
1474
1475         ldb.modify_ldif("""
1476 dn: <SID=""" + ldb.schema_format_value("objectSid", res[0]["objectSid"][0]) + """>
1477 changetype: modify
1478 delete: member
1479 """)
1480
1481         ldb.modify_ldif("""
1482 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1483 changetype: modify
1484 add: member
1485 member: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
1486 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
1487 """)
1488
1489         ldb.modify_ldif("""
1490 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1491 changetype: modify
1492 replace: member
1493 """)
1494
1495         ldb.modify_ldif("""
1496 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1497 changetype: modify
1498 add: member
1499 member: <SID=""" + ldb.schema_format_value("objectSid", res_user[0]["objectSid"][0]) + """>
1500 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
1501 """)
1502
1503         ldb.modify_ldif("""
1504 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1505 changetype: modify
1506 delete: member
1507 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
1508 """)
1509
1510         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
1511         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
1512
1513         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
1514         self.assertEquals(res[0]["member"][0], ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1515         self.assertEquals(len(res[0]["member"]), 1)
1516
1517         ldb.delete(("CN=ldaptestuser2,CN=Users," + self.base_dn))
1518
1519         time.sleep(4)
1520
1521         attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]
1522         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
1523         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
1524         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete")
1525
1526         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
1527         self.assertTrue("member" not in res[0])
1528
1529         print "Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))"
1530 # TODO UTF8 users don't seem to work fully anymore
1531 #        res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
1532         res = ldb.search(expression="(&(cn=ldaptestutf8user èùéìòà)(objectclass=user))")
1533         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
1534
1535         self.assertEquals(str(res[0].dn), ("CN=ldaptestutf8user èùéìòà,CN=Users," + self.base_dn))
1536         self.assertEquals(str(res[0]["cn"]), "ldaptestutf8user èùéìòà")
1537         self.assertEquals(str(res[0]["name"]), "ldaptestutf8user èùéìòà")
1538         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
1539         self.assertTrue("objectGUID" in res[0])
1540         self.assertTrue("whenCreated" in res[0])
1541
1542         ldb.delete(res[0].dn)
1543
1544         print "Testing ldb.search for (&(cn=ldaptestutf8user2*)(objectClass=user))"
1545         res = ldb.search(expression="(&(cn=ldaptestutf8user2*)(objectClass=user))")
1546         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user2*)(objectClass=user))")
1547
1548         ldb.delete(res[0].dn)
1549
1550         ldb.delete(("CN=ldaptestgroup2,CN=Users," + self.base_dn))
1551
1552         print "Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))"
1553 # TODO UTF8 users don't seem to work fully anymore
1554 #        res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
1555 #        self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
1556
1557         print "Testing that we can't get at the configuration DN from the main search base"
1558         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
1559         self.assertEquals(len(res), 0)
1560
1561         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"
1562         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
1563         self.assertTrue(len(res) > 0)
1564
1565         if gc_ldb is not None:
1566             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"
1567
1568             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:0"])
1569             self.assertTrue(len(res) > 0)
1570
1571             print "Testing that we do find configuration elements in the global catlog"
1572             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
1573             self.assertTrue(len(res) > 0)
1574
1575             print "Testing that we do find configuration elements and user elements at the same time"
1576             res = gc_ldb.search(self.base_dn, expression="(|(objectClass=crossRef)(objectClass=person))", scope=SCOPE_SUBTREE, attrs=["cn"])
1577             self.assertTrue(len(res) > 0)
1578
1579             print "Testing that we do find configuration elements in the global catlog, with the configuration basedn"
1580             res = gc_ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
1581             self.assertTrue(len(res) > 0)
1582
1583         print "Testing that we can get at the configuration DN on the main LDAP port"
1584         res = ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
1585         self.assertTrue(len(res) > 0)
1586
1587         print "Testing objectCategory canonacolisation"
1588         res = ldb.search(self.configuration_dn, expression="objectCategory=ntDsDSA", scope=SCOPE_SUBTREE, attrs=["cn"])
1589         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=ntDsDSA")
1590         self.assertTrue(len(res) != 0)
1591
1592         res = ldb.search(self.configuration_dn, expression="objectCategory=CN=ntDs-DSA," + self.schema_dn, scope=SCOPE_SUBTREE, attrs=["cn"])
1593         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=CN=ntDs-DSA," + self.schema_dn)
1594         self.assertTrue(len(res) != 0)
1595
1596         print "Testing objectClass attribute order on "+ self.base_dn
1597         res = ldb.search(expression="objectClass=domain", base=self.base_dn,
1598                          scope=SCOPE_BASE, attrs=["objectClass"])
1599         self.assertEquals(len(res), 1)
1600
1601         self.assertEquals(list(res[0]["objectClass"]), ["top", "domain", "domainDNS"])
1602
1603     #  check enumeration
1604
1605         print "Testing ldb.search for objectCategory=person"
1606         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"])
1607         self.assertTrue(len(res) > 0)
1608
1609         print "Testing ldb.search for objectCategory=person with domain scope control"
1610         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
1611         self.assertTrue(len(res) > 0)
1612
1613         print "Testing ldb.search for objectCategory=user"
1614         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"])
1615         self.assertTrue(len(res) > 0)
1616
1617         print "Testing ldb.search for objectCategory=user with domain scope control"
1618         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
1619         self.assertTrue(len(res) > 0)
1620
1621         print "Testing ldb.search for objectCategory=group"
1622         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"])
1623         self.assertTrue(len(res) > 0)
1624
1625         print "Testing ldb.search for objectCategory=group with domain scope control"
1626         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
1627         self.assertTrue(len(res) > 0)
1628
1629         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1630         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
1631         self.delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
1632         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
1633         self.delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
1634         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1635         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1636         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1637         self.delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
1638         self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
1639         self.delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
1640         self.delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
1641         self.delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1642         self.delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
1643
1644     def test_security_descriptor_add(self):
1645         """ Testing ldb.add_ldif() for nTSecurityDescriptor """
1646         user_name = "testdescriptoruser1"
1647         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
1648         #
1649         # Test add_ldif() with SDDL security descriptor input
1650         #
1651         self.delete_force(self.ldb, user_dn)
1652         try:
1653             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
1654             self.ldb.add_ldif("""
1655 dn: """ + user_dn + """
1656 objectclass: user
1657 sAMAccountName: """ + user_name + """
1658 nTSecurityDescriptor: """ + sddl)
1659             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1660             desc = res[0]["nTSecurityDescriptor"][0]
1661             desc = ndr_unpack( security.descriptor, desc )
1662             desc_sddl = desc.as_sddl( self.domain_sid )
1663             self.assertEqual(desc_sddl, sddl)
1664         finally:
1665             self.delete_force(self.ldb, user_dn)
1666         #
1667         # Test add_ldif() with BASE64 security descriptor
1668         #
1669         try:
1670             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
1671             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
1672             desc_binary = ndr_pack(desc)
1673             desc_base64 = base64.b64encode(desc_binary)
1674             self.ldb.add_ldif("""
1675 dn: """ + user_dn + """
1676 objectclass: user
1677 sAMAccountName: """ + user_name + """
1678 nTSecurityDescriptor:: """ + desc_base64)
1679             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1680             desc = res[0]["nTSecurityDescriptor"][0]
1681             desc = ndr_unpack(security.descriptor, desc)
1682             desc_sddl = desc.as_sddl(self.domain_sid)
1683             self.assertEqual(desc_sddl, sddl)
1684         finally:
1685             self.delete_force(self.ldb, user_dn)
1686
1687     def test_security_descriptor_add_neg(self):
1688         """Test add_ldif() with BASE64 security descriptor input using WRONG domain SID
1689             Negative test
1690         """
1691         user_name = "testdescriptoruser1"
1692         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
1693         self.delete_force(self.ldb, user_dn)
1694         try:
1695             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
1696             desc = security.descriptor.from_sddl(sddl, security.dom_sid('S-1-5-21'))
1697             desc_base64 = base64.b64encode( ndr_pack(desc) )
1698             self.ldb.add_ldif("""
1699 dn: """ + user_dn + """
1700 objectclass: user
1701 sAMAccountName: """ + user_name + """
1702 nTSecurityDescriptor:: """ + desc_base64)
1703             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1704             print res
1705             self.assertRaises(KeyError, lambda: res[0]["nTSecurityDescriptor"])
1706         finally:
1707             self.delete_force(self.ldb, user_dn)
1708
1709     def test_security_descriptor_modify(self):
1710         """ Testing ldb.modify_ldif() for nTSecurityDescriptor """
1711         user_name = "testdescriptoruser2"
1712         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
1713         #
1714         # Delete user object and test modify_ldif() with SDDL security descriptor input
1715         # Add ACE to the original descriptor test
1716         #
1717         try:
1718             self.delete_force(self.ldb, user_dn)
1719             self.ldb.add_ldif("""
1720 dn: """ + user_dn + """
1721 objectclass: user
1722 sAMAccountName: """ + user_name)
1723             # Modify descriptor
1724             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1725             desc = res[0]["nTSecurityDescriptor"][0]
1726             desc = ndr_unpack(security.descriptor, desc)
1727             desc_sddl = desc.as_sddl(self.domain_sid)
1728             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
1729             mod = """
1730 dn: """ + user_dn + """
1731 changetype: modify
1732 replace: nTSecurityDescriptor
1733 nTSecurityDescriptor: """ + sddl
1734             self.ldb.modify_ldif(mod)
1735             # Read modified descriptor
1736             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1737             desc = res[0]["nTSecurityDescriptor"][0]
1738             desc = ndr_unpack(security.descriptor, desc)
1739             desc_sddl = desc.as_sddl(self.domain_sid)
1740             self.assertEqual(desc_sddl, sddl)
1741         finally:
1742             self.delete_force(self.ldb, user_dn)
1743         #
1744         # Test modify_ldif() with SDDL security descriptor input
1745         # New desctiptor test
1746         #
1747         try:
1748             self.ldb.add_ldif("""
1749 dn: """ + user_dn + """
1750 objectclass: user
1751 sAMAccountName: """ + user_name)
1752             # Modify descriptor
1753             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
1754             mod = """
1755 dn: """ + user_dn + """
1756 changetype: modify
1757 replace: nTSecurityDescriptor
1758 nTSecurityDescriptor: """ + sddl
1759             self.ldb.modify_ldif(mod)
1760             # Read modified descriptor
1761             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1762             desc = res[0]["nTSecurityDescriptor"][0]
1763             desc = ndr_unpack(security.descriptor, desc)
1764             desc_sddl = desc.as_sddl(self.domain_sid)
1765             self.assertEqual(desc_sddl, sddl)
1766         finally:
1767             self.delete_force(self.ldb, user_dn)
1768         #
1769         # Test modify_ldif() with BASE64 security descriptor input
1770         # Add ACE to the original descriptor test
1771         #
1772         try:
1773             self.ldb.add_ldif("""
1774 dn: """ + user_dn + """
1775 objectclass: user
1776 sAMAccountName: """ + user_name)
1777             # Modify descriptor
1778             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1779             desc = res[0]["nTSecurityDescriptor"][0]
1780             desc = ndr_unpack(security.descriptor, desc)
1781             desc_sddl = desc.as_sddl(self.domain_sid)
1782             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
1783             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
1784             desc_base64 = base64.b64encode(ndr_pack(desc))
1785             mod = """
1786 dn: """ + user_dn + """
1787 changetype: modify
1788 replace: nTSecurityDescriptor
1789 nTSecurityDescriptor:: """ + desc_base64
1790             self.ldb.modify_ldif(mod)
1791             # Read modified descriptor
1792             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1793             desc = res[0]["nTSecurityDescriptor"][0]
1794             desc = ndr_unpack(security.descriptor, desc)
1795             desc_sddl = desc.as_sddl(self.domain_sid)
1796             self.assertEqual(desc_sddl, sddl)
1797         finally:
1798             self.delete_force(self.ldb, user_dn)
1799         #
1800         # Test modify_ldif() with BASE64 security descriptor input
1801         # New descriptor test
1802         #
1803         try:
1804             self.delete_force(self.ldb, user_dn)
1805             self.ldb.add_ldif("""
1806 dn: """ + user_dn + """
1807 objectclass: user
1808 sAMAccountName: """ + user_name)
1809             # Modify descriptor
1810             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
1811             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
1812             desc_base64 = base64.b64encode(ndr_pack(desc))
1813             mod = """
1814 dn: """ + user_dn + """
1815 changetype: modify
1816 replace: nTSecurityDescriptor
1817 nTSecurityDescriptor:: """ + desc_base64
1818             self.ldb.modify_ldif(mod)
1819             # Read modified descriptor
1820             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
1821             desc = res[0]["nTSecurityDescriptor"][0]
1822             desc = ndr_unpack(security.descriptor, desc)
1823             desc_sddl = desc.as_sddl(self.domain_sid)
1824             self.assertEqual(desc_sddl, sddl)
1825         finally:
1826             self.delete_force(self.ldb, user_dn)
1827
1828 class BaseDnTests(unittest.TestCase):
1829     def setUp(self):
1830         self.ldb = ldb
1831
1832     def test_rootdse_attrs(self):
1833         """Testing for all rootDSE attributes"""
1834         res = self.ldb.search(scope=SCOPE_BASE, attrs=[])
1835         self.assertEquals(len(res), 1)
1836
1837     def test_highestcommittedusn(self):
1838         """Testing for highestCommittedUSN"""
1839         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["highestCommittedUSN"])
1840         self.assertEquals(len(res), 1)
1841         self.assertTrue(int(res[0]["highestCommittedUSN"][0]) != 0)
1842
1843     def test_netlogon(self):
1844         """Testing for netlogon via LDAP"""
1845         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["netlogon"])
1846         self.assertEquals(len(res), 0)
1847
1848     def test_netlogon_highestcommitted_usn(self):
1849         """Testing for netlogon and highestCommittedUSN via LDAP"""
1850         res = self.ldb.search("", scope=SCOPE_BASE,
1851                 attrs=["netlogon", "highestCommittedUSN"])
1852         self.assertEquals(len(res), 0)
1853
1854 class SchemaTests(unittest.TestCase):
1855     def delete_force(self, ldb, dn):
1856         try:
1857             ldb.delete(dn)
1858         except LdbError, (num, _):
1859             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1860
1861     def find_schemadn(self, ldb):
1862         res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"])
1863         self.assertEquals(len(res), 1)
1864         return res[0]["schemaNamingContext"][0]
1865
1866     def find_basedn(self, ldb):
1867         res = ldb.search(base="", expression="", scope=SCOPE_BASE,
1868                          attrs=["defaultNamingContext"])
1869         self.assertEquals(len(res), 1)
1870         return res[0]["defaultNamingContext"][0]
1871
1872     def setUp(self):
1873         self.ldb = ldb
1874         self.schema_dn = self.find_schemadn(ldb)
1875         self.base_dn = self.find_basedn(ldb)
1876
1877     def test_generated_schema(self):
1878         """Testing we can read the generated schema via LDAP"""
1879         res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
1880                 attrs=["objectClasses", "attributeTypes", "dITContentRules"])
1881         self.assertEquals(len(res), 1)
1882         self.assertTrue("dITContentRules" in res[0])
1883         self.assertTrue("objectClasses" in res[0])
1884         self.assertTrue("attributeTypes" in res[0])
1885
1886     def test_generated_schema_is_operational(self):
1887         """Testing we don't get the generated schema via LDAP by default"""
1888         res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
1889                 attrs=["*"])
1890         self.assertEquals(len(res), 1)
1891         self.assertFalse("dITContentRules" in res[0])
1892         self.assertFalse("objectClasses" in res[0])
1893         self.assertFalse("attributeTypes" in res[0])
1894
1895
1896     def test_schemaUpdateNow(self):
1897         """Testing schemaUpdateNow"""
1898         attr_name = "test-Attr" + time.strftime("%s", time.gmtime())
1899         attr_ldap_display_name = attr_name.replace("-", "")
1900
1901         ldif = """
1902 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1903 objectClass: top
1904 objectClass: attributeSchema
1905 adminDescription: """ + attr_name + """
1906 adminDisplayName: """ + attr_name + """
1907 cn: """ + attr_name + """
1908 attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
1909 attributeSyntax: 2.5.5.12
1910 omSyntax: 64
1911 instanceType: 4
1912 isSingleValued: TRUE
1913 systemOnly: FALSE
1914 """
1915         self.ldb.add_ldif(ldif)
1916
1917         class_name = "test-Class" + time.strftime("%s", time.gmtime())
1918         class_ldap_display_name = class_name.replace("-", "")
1919
1920         ldif = """
1921 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1922 objectClass: top
1923 objectClass: classSchema
1924 adminDescription: """ + class_name + """
1925 adminDisplayName: """ + class_name + """
1926 cn: """ + class_name + """
1927 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
1928 instanceType: 4
1929 objectClassCategory: 1
1930 subClassOf: organizationalPerson
1931 systemFlags: 16
1932 rDNAttID: cn
1933 systemMustContain: cn, """ + attr_ldap_display_name + """
1934 systemOnly: FALSE
1935 """
1936         self.ldb.add_ldif(ldif)
1937
1938         ldif = """
1939 dn:
1940 changetype: modify
1941 add: schemaUpdateNow
1942 schemaUpdateNow: 1
1943 """
1944         self.ldb.modify_ldif(ldif)
1945
1946         object_name = "obj" + time.strftime("%s", time.gmtime())
1947
1948         ldif = """
1949 dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
1950 objectClass: organizationalPerson
1951 objectClass: person
1952 objectClass: """ + class_ldap_display_name + """
1953 objectClass: top
1954 cn: """ + object_name + """
1955 instanceType: 4
1956 objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """
1957 distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
1958 name: """ + object_name + """
1959 """ + attr_ldap_display_name + """: test
1960 """
1961         self.ldb.add_ldif(ldif)
1962
1963         # Search for created attribute
1964         res = []
1965         res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
1966         self.assertEquals(len(res), 1)
1967         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
1968
1969         # Search for created objectclass
1970         res = []
1971         res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
1972         self.assertEquals(len(res), 1)
1973         self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
1974         self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
1975
1976         # Search for created object
1977         res = []
1978         res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["*"])
1979         self.assertEquals(len(res), 1)
1980         # Delete the object
1981         self.delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
1982
1983 if not "://" in host:
1984     host = "ldap://%s" % host
1985
1986 ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
1987 gc_ldb = Ldb("%s:3268" % host, credentials=creds,
1988              session_info=system_session(), lp=lp)
1989
1990 runner = SubunitTestRunner()
1991 rc = 0
1992 if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful():
1993     rc = 1
1994 if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful():
1995     rc = 1
1996 if not runner.run(unittest.makeSuite(SchemaTests)).wasSuccessful():
1997     rc = 1
1998 sys.exit(rc)