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