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