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