2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2011
6 # Copyright (C) Catalyst.Net Ltd 2017
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 from __future__ import print_function
29 sys.path.insert(0, "bin/python")
31 from samba.tests.subunitrun import TestProgram, SubunitOptions
33 import samba.getopt as options
35 from samba.auth import system_session
36 from ldb import SCOPE_ONELEVEL, SCOPE_BASE, LdbError
37 from ldb import ERR_NO_SUCH_OBJECT
38 from ldb import ERR_UNWILLING_TO_PERFORM
39 from ldb import ERR_ENTRY_ALREADY_EXISTS
40 from ldb import ERR_CONSTRAINT_VIOLATION
41 from ldb import ERR_OBJECT_CLASS_VIOLATION
42 from ldb import Message, MessageElement, Dn
43 from ldb import FLAG_MOD_REPLACE
44 from samba.samdb import SamDB
45 from samba.dsdb import DS_DOMAIN_FUNCTION_2003
46 from samba.tests import delete_force
47 from samba.ndr import ndr_unpack
48 from samba.dcerpc import drsblobs
50 parser = optparse.OptionParser("ldap_schema.py [options] <host>")
51 sambaopts = options.SambaOptions(parser)
52 parser.add_option_group(sambaopts)
53 parser.add_option_group(options.VersionOptions(parser))
54 # use command line creds if available
55 credopts = options.CredentialsOptions(parser)
56 parser.add_option_group(credopts)
57 subunitopts = SubunitOptions(parser)
58 parser.add_option_group(subunitopts)
59 opts, args = parser.parse_args()
67 lp = sambaopts.get_loadparm()
68 creds = credopts.get_credentials(lp)
71 class SchemaTests(samba.tests.TestCase):
74 super(SchemaTests, self).setUp()
75 self.ldb = SamDB(host, credentials=creds,
76 session_info=system_session(lp), lp=lp, options=ldb_options)
77 self.base_dn = self.ldb.domain_dn()
78 self.schema_dn = self.ldb.get_schema_basedn().get_linearized()
80 def test_generated_schema(self):
81 """Testing we can read the generated schema via LDAP"""
82 res = self.ldb.search("cn=aggregate," + self.schema_dn, scope=SCOPE_BASE,
83 attrs=["objectClasses", "attributeTypes", "dITContentRules"])
84 self.assertEquals(len(res), 1)
85 self.assertTrue("dITContentRules" in res[0])
86 self.assertTrue("objectClasses" in res[0])
87 self.assertTrue("attributeTypes" in res[0])
89 def test_generated_schema_is_operational(self):
90 """Testing we don't get the generated schema via LDAP by default"""
91 # Must keep the "*" form
92 res = self.ldb.search("cn=aggregate," + self.schema_dn, scope=SCOPE_BASE,
94 self.assertEquals(len(res), 1)
95 self.assertFalse("dITContentRules" in res[0])
96 self.assertFalse("objectClasses" in res[0])
97 self.assertFalse("attributeTypes" in res[0])
99 def test_schemaUpdateNow(self):
100 """Testing schemaUpdateNow"""
101 rand = str(random.randint(1, 100000))
102 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
103 attr_ldap_display_name = attr_name.replace("-", "")
106 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
108 objectClass: attributeSchema
109 adminDescription: """ + attr_name + """
110 adminDisplayName: """ + attr_name + """
111 cn: """ + attr_name + """
112 attributeId: 1.3.6.1.4.1.7165.4.6.1.6.1.""" + rand + """
113 attributeSyntax: 2.5.5.12
119 self.ldb.add_ldif(ldif)
120 # We must do a schemaUpdateNow otherwise it's not 100% sure that the schema
121 # will contain the new attribute
128 self.ldb.modify_ldif(ldif)
130 # Search for created attribute
132 res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE,
133 attrs=["lDAPDisplayName", "schemaIDGUID", "msDS-IntID"])
134 self.assertEquals(len(res), 1)
135 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
136 self.assertTrue("schemaIDGUID" in res[0])
137 if "msDS-IntId" in res[0]:
138 msDS_IntId = int(res[0]["msDS-IntId"][0])
140 msDS_IntId += (1 << 32)
144 class_name = "test-Class" + time.strftime("%s", time.gmtime())
145 class_ldap_display_name = class_name.replace("-", "")
147 # First try to create a class with a wrong "defaultObjectCategory"
149 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
151 objectClass: classSchema
152 defaultObjectCategory: CN=_
153 adminDescription: """ + class_name + """
154 adminDisplayName: """ + class_name + """
155 cn: """ + class_name + """
156 governsId: 1.3.6.1.4.1.7165.4.6.2.6.1.""" + str(random.randint(1, 100000)) + """
158 objectClassCategory: 1
159 subClassOf: organizationalPerson
162 systemMustContain: cn
163 systemMustContain: """ + attr_ldap_display_name + """
167 self.ldb.add_ldif(ldif)
169 except LdbError as e1:
171 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
174 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
176 objectClass: classSchema
177 adminDescription: """ + class_name + """
178 adminDisplayName: """ + class_name + """
179 cn: """ + class_name + """
180 governsId: 1.3.6.1.4.1.7165.4.6.2.6.2.""" + str(random.randint(1, 100000)) + """
182 objectClassCategory: 1
183 subClassOf: organizationalPerson
186 systemMustContain: cn
187 systemMustContain: """ + attr_ldap_display_name + """
190 self.ldb.add_ldif(ldif)
192 # Search for created objectclass
194 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
195 attrs=["lDAPDisplayName", "defaultObjectCategory", "schemaIDGUID", "distinguishedName"])
196 self.assertEquals(len(res), 1)
197 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
198 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
199 self.assertTrue("schemaIDGUID" in res[0])
207 self.ldb.modify_ldif(ldif)
209 object_name = "obj" + time.strftime("%s", time.gmtime())
212 dn: CN=%s,CN=Users,%s""" % (object_name, self.base_dn) + """
213 objectClass: organizationalPerson
215 objectClass: """ + class_ldap_display_name + """
217 cn: """ + object_name + """
219 objectCategory: CN=%s,%s""" % (class_name, self.schema_dn) + """
220 distinguishedName: CN=%s,CN=Users,%s""" % (object_name, self.base_dn) + """
221 name: """ + object_name + """
222 """ + attr_ldap_display_name + """: test
224 self.ldb.add_ldif(ldif)
226 # Search for created object
227 obj_res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["replPropertyMetaData"])
229 self.assertEquals(len(obj_res), 1)
230 self.assertTrue("replPropertyMetaData" in obj_res[0])
231 val = obj_res[0]["replPropertyMetaData"][0]
232 repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
235 # Windows 2000 functional level won't have this. It is too
236 # hard to work it out from the prefixmap however, so we skip
237 # this test in that case.
238 if msDS_IntId is not None:
240 for o in repl.ctr.array:
241 if o.attid == msDS_IntId:
244 self.assertTrue(found, "Did not find 0x%08x in replPropertyMetaData" % msDS_IntId)
246 delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
248 def test_subClassOf(self):
249 """ Testing usage of custom child schamaClass
252 class_name = "my-Class" + time.strftime("%s", time.gmtime())
253 class_ldap_display_name = class_name.replace("-", "")
256 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
258 objectClass: classSchema
259 adminDescription: """ + class_name + """
260 adminDisplayName: """ + class_name + """
261 cn: """ + class_name + """
262 governsId: 1.3.6.1.4.1.7165.4.6.2.6.3.""" + str(random.randint(1, 100000)) + """
264 objectClassCategory: 1
265 subClassOf: organizationalUnit
269 self.ldb.add_ldif(ldif)
271 # Search for created objectclass
273 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
274 attrs=["lDAPDisplayName", "defaultObjectCategory",
275 "schemaIDGUID", "distinguishedName"])
276 self.assertEquals(len(res), 1)
277 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
278 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
279 self.assertTrue("schemaIDGUID" in res[0])
287 self.ldb.modify_ldif(ldif)
289 object_name = "org" + time.strftime("%s", time.gmtime())
292 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
293 objectClass: """ + class_ldap_display_name + """
294 ou: """ + object_name + """
297 self.ldb.add_ldif(ldif)
299 # Search for created object
301 res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
302 self.assertEquals(len(res), 1)
304 delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
306 def test_duplicate_attributeID(self):
307 """Testing creating a duplicate attribute"""
308 rand = str(random.randint(1, 100000))
309 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
310 attr_ldap_display_name = attr_name.replace("-", "")
311 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.2." + rand
313 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
315 objectClass: attributeSchema
316 adminDescription: """ + attr_name + """
317 adminDisplayName: """ + attr_name + """
318 cn: """ + attr_name + """
319 attributeId: """ + attributeID + """
320 attributeSyntax: 2.5.5.12
326 self.ldb.add_ldif(ldif)
329 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
331 objectClass: attributeSchema
332 adminDescription: """ + attr_name + """dup
333 adminDisplayName: """ + attr_name + """dup
334 cn: """ + attr_name + """-dup
335 attributeId: """ + attributeID + """
336 attributeSyntax: 2.5.5.12
343 self.ldb.add_ldif(ldif)
344 self.fail("Should have failed to add duplicate attributeID value")
345 except LdbError as e2:
346 (enum, estr) = e2.args
347 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
349 def test_duplicate_attributeID_governsID(self):
350 """Testing creating a duplicate attribute and class"""
351 rand = str(random.randint(1, 100000))
352 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
353 attr_ldap_display_name = attr_name.replace("-", "")
354 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.3." + rand
356 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
358 objectClass: attributeSchema
359 adminDescription: """ + attr_name + """
360 adminDisplayName: """ + attr_name + """
361 cn: """ + attr_name + """
362 attributeId: """ + attributeID + """
363 attributeSyntax: 2.5.5.12
369 self.ldb.add_ldif(ldif)
372 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
374 objectClass: classSchema
375 adminDescription: """ + attr_name + """dup
376 adminDisplayName: """ + attr_name + """dup
377 cn: """ + attr_name + """-dup
378 governsId: """ + attributeID + """
380 objectClassCategory: 1
381 subClassOf: organizationalPerson
383 systemMustContain: cn
387 self.ldb.add_ldif(ldif)
388 self.fail("Should have failed to add duplicate governsID conflicting with attributeID value")
389 except LdbError as e3:
390 (enum, estr) = e3.args
391 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
393 def test_duplicate_cn(self):
394 """Testing creating a duplicate attribute"""
395 rand = str(random.randint(1, 100000))
396 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
397 attr_ldap_display_name = attr_name.replace("-", "")
398 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.4." + rand
400 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
402 objectClass: attributeSchema
403 adminDescription: """ + attr_name + """
404 adminDisplayName: """ + attr_name + """
405 cn: """ + attr_name + """
406 attributeId: """ + attributeID + """
407 attributeSyntax: 2.5.5.12
413 self.ldb.add_ldif(ldif)
416 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
418 objectClass: attributeSchema
419 adminDescription: """ + attr_name + """dup
420 adminDisplayName: """ + attr_name + """dup
421 cn: """ + attr_name + """
422 attributeId: """ + attributeID + """.1
423 attributeSyntax: 2.5.5.12
430 self.ldb.add_ldif(ldif)
431 self.fail("Should have failed to add attribute with duplicate CN")
432 except LdbError as e4:
433 (enum, estr) = e4.args
434 self.assertEquals(enum, ERR_ENTRY_ALREADY_EXISTS)
436 def test_duplicate_implicit_ldapdisplayname(self):
437 """Testing creating a duplicate attribute ldapdisplayname"""
438 rand = str(random.randint(1, 100000))
439 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
440 attr_ldap_display_name = attr_name.replace("-", "")
441 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.5." + rand
443 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
445 objectClass: attributeSchema
446 adminDescription: """ + attr_name + """
447 adminDisplayName: """ + attr_name + """
448 cn: """ + attr_name + """
449 attributeId: """ + attributeID + """
450 attributeSyntax: 2.5.5.12
456 self.ldb.add_ldif(ldif)
459 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
461 objectClass: attributeSchema
462 adminDescription: """ + attr_name + """dup
463 adminDisplayName: """ + attr_name + """dup
464 cn: """ + attr_name + """-dup
465 ldapDisplayName: """ + attr_ldap_display_name + """
466 attributeId: """ + attributeID + """.1
467 attributeSyntax: 2.5.5.12
474 self.ldb.add_ldif(ldif)
475 self.fail("Should have failed to add attribute with duplicate of the implicit ldapDisplayName")
476 except LdbError as e5:
477 (enum, estr) = e5.args
478 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
480 def test_duplicate_explicit_ldapdisplayname(self):
481 """Testing creating a duplicate attribute ldapdisplayname"""
482 rand = str(random.randint(1, 100000))
483 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
484 attr_ldap_display_name = attr_name.replace("-", "")
485 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.6." + rand
487 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
489 objectClass: attributeSchema
490 adminDescription: """ + attr_name + """
491 adminDisplayName: """ + attr_name + """
492 cn: """ + attr_name + """
493 attributeId: """ + attributeID + """
494 attributeSyntax: 2.5.5.12
495 ldapDisplayName: """ + attr_ldap_display_name + """
501 self.ldb.add_ldif(ldif)
504 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
506 objectClass: attributeSchema
507 adminDescription: """ + attr_name + """dup
508 adminDisplayName: """ + attr_name + """dup
509 cn: """ + attr_name + """-dup
510 ldapDisplayName: """ + attr_ldap_display_name + """
511 attributeId: """ + attributeID + """.1
512 attributeSyntax: 2.5.5.12
519 self.ldb.add_ldif(ldif)
520 self.fail("Should have failed to add attribute with duplicate ldapDisplayName")
521 except LdbError as e6:
522 (enum, estr) = e6.args
523 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
525 def test_duplicate_explicit_ldapdisplayname_with_class(self):
526 """Testing creating a duplicate attribute ldapdisplayname between
527 and attribute and a class"""
528 rand = str(random.randint(1, 100000))
529 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
530 attr_ldap_display_name = attr_name.replace("-", "")
531 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.7." + rand
532 governsID = "1.3.6.1.4.1.7165.4.6.2.6.4." + rand
534 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
536 objectClass: attributeSchema
537 adminDescription: """ + attr_name + """
538 adminDisplayName: """ + attr_name + """
539 cn: """ + attr_name + """
540 attributeId: """ + attributeID + """
541 attributeSyntax: 2.5.5.12
542 ldapDisplayName: """ + attr_ldap_display_name + """
548 self.ldb.add_ldif(ldif)
551 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
553 objectClass: classSchema
554 adminDescription: """ + attr_name + """dup
555 adminDisplayName: """ + attr_name + """dup
556 cn: """ + attr_name + """-dup
557 ldapDisplayName: """ + attr_ldap_display_name + """
558 governsID: """ + governsID + """
560 objectClassCategory: 1
561 subClassOf: organizationalPerson
563 systemMustContain: cn
567 self.ldb.add_ldif(ldif)
568 self.fail("Should have failed to add class with duplicate ldapDisplayName")
569 except LdbError as e7:
570 (enum, estr) = e7.args
571 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
573 def test_duplicate_via_rename_ldapdisplayname(self):
574 """Testing creating a duplicate attribute ldapdisplayname"""
575 rand = str(random.randint(1, 100000))
576 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
577 attr_ldap_display_name = attr_name.replace("-", "")
578 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.8." + rand
580 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
582 objectClass: attributeSchema
583 adminDescription: """ + attr_name + """
584 adminDisplayName: """ + attr_name + """
585 cn: """ + attr_name + """
586 attributeId: """ + attributeID + """
587 attributeSyntax: 2.5.5.12
588 ldapDisplayName: """ + attr_ldap_display_name + """
594 self.ldb.add_ldif(ldif)
597 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
599 objectClass: attributeSchema
600 adminDescription: """ + attr_name + """dup
601 adminDisplayName: """ + attr_name + """dup
602 cn: """ + attr_name + """-dup
603 ldapDisplayName: """ + attr_ldap_display_name + """dup
604 attributeId: """ + attributeID + """.1
605 attributeSyntax: 2.5.5.12
611 self.ldb.add_ldif(ldif)
614 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
616 replace: ldapDisplayName
617 ldapDisplayName: """ + attr_ldap_display_name + """
621 self.ldb.modify_ldif(ldif)
622 self.fail("Should have failed to modify schema to have attribute with duplicate ldapDisplayName")
623 except LdbError as e8:
624 (enum, estr) = e8.args
625 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
627 def test_duplicate_via_rename_attributeID(self):
628 """Testing creating a duplicate attributeID"""
629 rand = str(random.randint(1, 100000))
630 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
631 attr_ldap_display_name = attr_name.replace("-", "")
632 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.9." + rand
634 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
636 objectClass: attributeSchema
637 adminDescription: """ + attr_name + """
638 adminDisplayName: """ + attr_name + """
639 cn: """ + attr_name + """
640 attributeId: """ + attributeID + """
641 attributeSyntax: 2.5.5.12
642 ldapDisplayName: """ + attr_ldap_display_name + """
648 self.ldb.add_ldif(ldif)
651 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
653 objectClass: attributeSchema
654 adminDescription: """ + attr_name + """dup
655 adminDisplayName: """ + attr_name + """dup
656 cn: """ + attr_name + """-dup
657 ldapDisplayName: """ + attr_ldap_display_name + """dup
658 attributeId: """ + attributeID + """.1
659 attributeSyntax: 2.5.5.12
665 self.ldb.add_ldif(ldif)
668 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
671 attributeId: """ + attributeID + """
675 self.ldb.modify_ldif(ldif)
676 self.fail("Should have failed to modify schema to have attribute with duplicate attributeID")
677 except LdbError as e9:
678 (enum, estr) = e9.args
679 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
681 def test_remove_ldapdisplayname(self):
682 """Testing removing the ldapdisplayname"""
683 rand = str(random.randint(1, 100000))
684 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
685 attr_ldap_display_name = attr_name.replace("-", "")
686 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.10." + rand
688 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
690 objectClass: attributeSchema
691 adminDescription: """ + attr_name + """
692 adminDisplayName: """ + attr_name + """
693 cn: """ + attr_name + """
694 attributeId: """ + attributeID + """
695 attributeSyntax: 2.5.5.12
696 ldapDisplayName: """ + attr_ldap_display_name + """
702 self.ldb.add_ldif(ldif)
705 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
707 replace: ldapDisplayName
711 self.ldb.modify_ldif(ldif)
712 self.fail("Should have failed to remove the ldapdisplayname")
713 except LdbError as e10:
714 (enum, estr) = e10.args
715 self.assertEquals(enum, ERR_OBJECT_CLASS_VIOLATION)
717 def test_rename_ldapdisplayname(self):
718 """Testing renaming ldapdisplayname"""
719 rand = str(random.randint(1, 100000))
720 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
721 attr_ldap_display_name = attr_name.replace("-", "")
722 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.11." + rand
724 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
726 objectClass: attributeSchema
727 adminDescription: """ + attr_name + """
728 adminDisplayName: """ + attr_name + """
729 cn: """ + attr_name + """
730 attributeId: """ + attributeID + """
731 attributeSyntax: 2.5.5.12
732 ldapDisplayName: """ + attr_ldap_display_name + """
738 self.ldb.add_ldif(ldif)
741 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
743 replace: ldapDisplayName
744 ldapDisplayName: """ + attr_ldap_display_name + """2
747 self.ldb.modify_ldif(ldif)
749 def test_change_attributeID(self):
750 """Testing change the attributeID"""
751 rand = str(random.randint(1, 100000))
752 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
753 attr_ldap_display_name = attr_name.replace("-", "")
754 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.12." + rand
756 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
758 objectClass: attributeSchema
759 adminDescription: """ + attr_name + """
760 adminDisplayName: """ + attr_name + """
761 cn: """ + attr_name + """
762 attributeId: """ + attributeID + """
763 attributeSyntax: 2.5.5.12
764 ldapDisplayName: """ + attr_ldap_display_name + """
770 self.ldb.add_ldif(ldif)
773 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
776 attributeId: """ + attributeID + """.1
780 self.ldb.modify_ldif(ldif)
781 self.fail("Should have failed to modify schema to have different attributeID")
782 except LdbError as e11:
783 (enum, estr) = e11.args
784 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
786 def test_change_attributeID_same(self):
787 """Testing change the attributeID to the same value"""
788 rand = str(random.randint(1, 100000))
789 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
790 attr_ldap_display_name = attr_name.replace("-", "")
791 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.13." + rand
793 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
795 objectClass: attributeSchema
796 adminDescription: """ + attr_name + """
797 adminDisplayName: """ + attr_name + """
798 cn: """ + attr_name + """
799 attributeId: """ + attributeID + """
800 attributeSyntax: 2.5.5.12
801 ldapDisplayName: """ + attr_ldap_display_name + """
807 self.ldb.add_ldif(ldif)
810 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
813 attributeId: """ + attributeID + """
817 self.ldb.modify_ldif(ldif)
818 self.fail("Should have failed to modify schema to have the same attributeID")
819 except LdbError as e12:
820 (enum, estr) = e12.args
821 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
823 def test_generated_linkID(self):
825 Test that we automatically generate a linkID if the
826 OID "1.2.840.113556.1.2.50" is given as the linkID
827 of a new attribute, and that we don't get/can't add
828 duplicate linkIDs. Also test that we can add a backlink
829 by providing the attributeID or ldapDisplayName of
830 a forwards link in the linkID attribute.
833 # linkID generation isn't available before 2003
834 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
835 attrs=["domainControllerFunctionality"])
836 self.assertEquals(len(res), 1)
837 dc_level = int(res[0]["domainControllerFunctionality"][0])
838 if dc_level < DS_DOMAIN_FUNCTION_2003:
841 rand = str(random.randint(1, 100000))
843 attr_name_1 = "test-generated-linkID" + time.strftime("%s", time.gmtime()) + "-" + rand
844 attr_ldap_display_name_1 = attr_name_1.replace("-", "")
845 attributeID_1 = "1.3.6.1.4.1.7165.4.6.1.6.16." + rand
847 dn: CN=%s,%s""" % (attr_name_1, self.schema_dn) + """
849 objectClass: attributeSchema
850 adminDescription: """ + attr_name_1 + """
851 adminDisplayName: """ + attr_name_1 + """
852 cn: """ + attr_name_1 + """
853 attributeId: """ + attributeID_1 + """
854 linkID: 1.2.840.113556.1.2.50
855 attributeSyntax: 2.5.5.1
856 ldapDisplayName: """ + attr_ldap_display_name_1 + """
864 self.ldb.add_ldif(ldif)
865 except LdbError as e13:
866 (enum, estr) = e13.args
869 attr_name_2 = "test-generated-linkID-2" + time.strftime("%s", time.gmtime()) + "-" + rand
870 attr_ldap_display_name_2 = attr_name_2.replace("-", "")
871 attributeID_2 = "1.3.6.1.4.1.7165.4.6.1.6.17." + rand
873 dn: CN=%s,%s""" % (attr_name_2, self.schema_dn) + """
875 objectClass: attributeSchema
876 adminDescription: """ + attr_name_2 + """
877 adminDisplayName: """ + attr_name_2 + """
878 cn: """ + attr_name_2 + """
879 attributeId: """ + attributeID_2 + """
880 linkID: 1.2.840.113556.1.2.50
881 attributeSyntax: 2.5.5.1
882 ldapDisplayName: """ + attr_ldap_display_name_2 + """
890 self.ldb.add_ldif(ldif)
891 except LdbError as e14:
892 (enum, estr) = e14.args
895 res = self.ldb.search("CN=%s,%s" % (attr_name_1, self.schema_dn),
898 self.assertEquals(len(res), 1)
899 linkID_1 = int(res[0]["linkID"][0])
901 res = self.ldb.search("CN=%s,%s" % (attr_name_2, self.schema_dn),
904 self.assertEquals(len(res), 1)
905 linkID_2 = int(res[0]["linkID"][0])
907 # 0 should never be generated as a linkID
908 self.assertFalse(linkID_1 == 0)
909 self.assertFalse(linkID_2 == 0)
911 # The generated linkID should always be even, because
912 # it should assume we're adding a forward link.
913 self.assertTrue(linkID_1 % 2 == 0)
914 self.assertTrue(linkID_2 % 2 == 0)
916 self.assertFalse(linkID_1 == linkID_2)
918 # This is only necessary against Windows, since we depend
919 # on the previously added links in the next ones and Windows
920 # won't refresh the schema as we add them.
924 replace: schemaupdatenow
927 self.ldb.modify_ldif(ldif)
929 # If we add a new link with the same linkID, it should fail
930 attr_name = "test-generated-linkID-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
931 attr_ldap_display_name = attr_name.replace("-", "")
932 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.18." + rand
934 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
936 objectClass: attributeSchema
937 adminDescription: """ + attr_name + """
938 adminDisplayName: """ + attr_name + """
939 cn: """ + attr_name + """
940 attributeId: """ + attributeID + """
941 linkID: """ + str(linkID_1) + """
942 attributeSyntax: 2.5.5.1
943 ldapDisplayName: """ + attr_ldap_display_name + """
951 self.ldb.add_ldif(ldif)
952 self.fail("Should have failed to add duplicate linkID value")
953 except LdbError as e15:
954 (enum, estr) = e15.args
955 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
957 # If we add another attribute with the attributeID or lDAPDisplayName
958 # of a forward link in its linkID field, it should add as a backlink
960 attr_name_3 = "test-generated-linkID-backlink" + time.strftime("%s", time.gmtime()) + "-" + rand
961 attr_ldap_display_name_3 = attr_name_3.replace("-", "")
962 attributeID_3 = "1.3.6.1.4.1.7165.4.6.1.6.19." + rand
964 dn: CN=%s,%s""" % (attr_name_3, self.schema_dn) + """
966 objectClass: attributeSchema
967 adminDescription: """ + attr_name_3 + """
968 adminDisplayName: """ + attr_name_3 + """
969 cn: """ + attr_name_3 + """
970 attributeId: """ + attributeID_3 + """
971 linkID: """ + str(linkID_1 + 1) + """
972 attributeSyntax: 2.5.5.1
973 ldapDisplayName: """ + attr_ldap_display_name_3 + """
981 self.ldb.add_ldif(ldif)
982 except LdbError as e16:
983 (enum, estr) = e16.args
986 res = self.ldb.search("CN=%s,%s" % (attr_name_3, self.schema_dn),
989 self.assertEquals(len(res), 1)
990 linkID = int(res[0]["linkID"][0])
991 self.assertEquals(linkID, linkID_1 + 1)
993 attr_name_4 = "test-generated-linkID-backlink-2" + time.strftime("%s", time.gmtime()) + "-" + rand
994 attr_ldap_display_name_4 = attr_name_4.replace("-", "")
995 attributeID_4 = "1.3.6.1.4.1.7165.4.6.1.6.20." + rand
997 dn: CN=%s,%s""" % (attr_name_4, self.schema_dn) + """
999 objectClass: attributeSchema
1000 adminDescription: """ + attr_name_4 + """
1001 adminDisplayName: """ + attr_name_4 + """
1002 cn: """ + attr_name_4 + """
1003 attributeId: """ + attributeID_4 + """
1004 linkID: """ + attr_ldap_display_name_2 + """
1005 attributeSyntax: 2.5.5.1
1006 ldapDisplayName: """ + attr_ldap_display_name_4 + """
1009 isSingleValued: TRUE
1014 self.ldb.add_ldif(ldif)
1015 except LdbError as e17:
1016 (enum, estr) = e17.args
1019 res = self.ldb.search("CN=%s,%s" % (attr_name_4, self.schema_dn),
1022 self.assertEquals(len(res), 1)
1023 linkID = int(res[0]["linkID"][0])
1024 self.assertEquals(linkID, linkID_2 + 1)
1026 # If we then try to add another backlink in the same way
1027 # for the same forwards link, we should fail.
1029 attr_name = "test-generated-linkID-backlink-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
1030 attr_ldap_display_name = attr_name.replace("-", "")
1031 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.21." + rand
1033 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1035 objectClass: attributeSchema
1036 adminDescription: """ + attr_name + """
1037 adminDisplayName: """ + attr_name + """
1038 cn: """ + attr_name + """
1039 attributeId: """ + attributeID + """
1040 linkID: """ + attributeID_1 + """
1041 attributeSyntax: 2.5.5.1
1042 ldapDisplayName: """ + attr_ldap_display_name + """
1045 isSingleValued: TRUE
1050 self.ldb.add_ldif(ldif)
1051 self.fail("Should have failed to add duplicate backlink")
1052 except LdbError as e18:
1053 (enum, estr) = e18.args
1054 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1056 # If we try to supply the attributeID or ldapDisplayName
1057 # of an existing backlink in the linkID field of a new link,
1060 attr_name = "test-generated-linkID-backlink-invalid" + time.strftime("%s", time.gmtime()) + "-" + rand
1061 attr_ldap_display_name = attr_name.replace("-", "")
1062 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.22." + rand
1064 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1066 objectClass: attributeSchema
1067 adminDescription: """ + attr_name + """
1068 adminDisplayName: """ + attr_name + """
1069 cn: """ + attr_name + """
1070 attributeId: """ + attributeID + """
1071 linkID: """ + attributeID_3 + """
1072 attributeSyntax: 2.5.5.1
1073 ldapDisplayName: """ + attr_ldap_display_name + """
1076 isSingleValued: TRUE
1081 self.ldb.add_ldif(ldif)
1082 self.fail("Should have failed to add backlink of backlink")
1083 except LdbError as e19:
1084 (enum, estr) = e19.args
1085 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1087 attr_name = "test-generated-linkID-backlink-invalid-2" + time.strftime("%s", time.gmtime()) + "-" + rand
1088 attr_ldap_display_name = attr_name.replace("-", "")
1089 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.23." + rand
1091 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1093 objectClass: attributeSchema
1094 adminDescription: """ + attr_name + """
1095 adminDisplayName: """ + attr_name + """
1096 cn: """ + attr_name + """
1097 attributeId: """ + attributeID + """
1098 linkID: """ + attr_ldap_display_name_4 + """
1099 attributeSyntax: 2.5.5.1
1100 ldapDisplayName: """ + attr_ldap_display_name + """
1103 isSingleValued: TRUE
1108 self.ldb.add_ldif(ldif)
1109 self.fail("Should have failed to add backlink of backlink")
1110 except LdbError as e20:
1111 (enum, estr) = e20.args
1112 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1114 def test_generated_mAPIID(self):
1116 Test that we automatically generate a mAPIID if the
1117 OID "1.2.840.113556.1.2.49" is given as the mAPIID
1118 of a new attribute, and that we don't get/can't add
1122 rand = str(random.randint(1, 100000))
1124 attr_name_1 = "test-generated-mAPIID" + time.strftime("%s", time.gmtime()) + "-" + rand
1125 attr_ldap_display_name_1 = attr_name_1.replace("-", "")
1126 attributeID_1 = "1.3.6.1.4.1.7165.4.6.1.6.24." + rand
1128 dn: CN=%s,%s""" % (attr_name_1, self.schema_dn) + """
1130 objectClass: attributeSchema
1131 adminDescription: """ + attr_name_1 + """
1132 adminDisplayName: """ + attr_name_1 + """
1133 cn: """ + attr_name_1 + """
1134 attributeId: """ + attributeID_1 + """
1135 mAPIID: 1.2.840.113556.1.2.49
1136 attributeSyntax: 2.5.5.1
1137 ldapDisplayName: """ + attr_ldap_display_name_1 + """
1140 isSingleValued: TRUE
1145 self.ldb.add_ldif(ldif)
1146 except LdbError as e21:
1147 (enum, estr) = e21.args
1150 res = self.ldb.search("CN=%s,%s" % (attr_name_1, self.schema_dn),
1153 self.assertEquals(len(res), 1)
1154 mAPIID_1 = int(res[0]["mAPIID"][0])
1159 replace: schemaupdatenow
1162 self.ldb.modify_ldif(ldif)
1164 # If we add a new attribute with the same mAPIID, it should fail
1165 attr_name = "test-generated-mAPIID-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
1166 attr_ldap_display_name = attr_name.replace("-", "")
1167 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.25." + rand
1169 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1171 objectClass: attributeSchema
1172 adminDescription: """ + attr_name + """
1173 adminDisplayName: """ + attr_name + """
1174 cn: """ + attr_name + """
1175 attributeId: """ + attributeID + """
1176 mAPIID: """ + str(mAPIID_1) + """
1177 attributeSyntax: 2.5.5.1
1178 ldapDisplayName: """ + attr_ldap_display_name + """
1181 isSingleValued: TRUE
1186 self.ldb.add_ldif(ldif)
1187 self.fail("Should have failed to add duplicate mAPIID value")
1188 except LdbError as e22:
1189 (enum, estr) = e22.args
1190 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1192 def test_change_governsID(self):
1193 """Testing change the governsID"""
1194 rand = str(random.randint(1, 100000))
1195 class_name = "test-Class" + time.strftime("%s", time.gmtime()) + "-" + rand
1196 class_ldap_display_name = class_name.replace("-", "")
1197 governsID = "1.3.6.1.4.1.7165.4.6.2.6.5." + rand
1199 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1201 objectClass: classSchema
1202 adminDescription: """ + class_name + """
1203 adminDisplayName: """ + class_name + """
1204 cn: """ + class_name + """
1205 governsId: """ + governsID + """
1206 ldapDisplayName: """ + class_ldap_display_name + """
1208 objectClassCategory: 1
1209 subClassOf: organizationalPerson
1211 systemMustContain: cn
1214 self.ldb.add_ldif(ldif)
1217 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1220 governsId: """ + governsID + """.1
1224 self.ldb.modify_ldif(ldif)
1225 self.fail("Should have failed to modify schema to have different governsID")
1226 except LdbError as e23:
1227 (enum, estr) = e23.args
1228 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
1230 def test_change_governsID_same(self):
1231 """Testing change the governsID"""
1232 rand = str(random.randint(1, 100000))
1233 class_name = "test-Class" + time.strftime("%s", time.gmtime()) + "-" + rand
1234 class_ldap_display_name = class_name.replace("-", "")
1235 governsID = "1.3.6.1.4.1.7165.4.6.2.6.6." + rand
1237 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1239 objectClass: classSchema
1240 adminDescription: """ + class_name + """
1241 adminDisplayName: """ + class_name + """
1242 cn: """ + class_name + """
1243 governsId: """ + governsID + """
1244 ldapDisplayName: """ + class_ldap_display_name + """
1246 objectClassCategory: 1
1247 subClassOf: organizationalPerson
1249 systemMustContain: cn
1252 self.ldb.add_ldif(ldif)
1255 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1258 governsId: """ + governsID + """.1
1262 self.ldb.modify_ldif(ldif)
1263 self.fail("Should have failed to modify schema to have the same governsID")
1264 except LdbError as e24:
1265 (enum, estr) = e24.args
1266 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
1268 def test_subClassOf(self):
1269 """ Testing usage of custom child classSchema
1272 class_name = "my-Class" + time.strftime("%s", time.gmtime())
1273 class_ldap_display_name = class_name.replace("-", "")
1276 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1278 objectClass: classSchema
1279 adminDescription: """ + class_name + """
1280 adminDisplayName: """ + class_name + """
1281 cn: """ + class_name + """
1282 governsId: 1.3.6.1.4.1.7165.4.6.2.6.7.""" + str(random.randint(1, 100000)) + """
1284 objectClassCategory: 1
1285 subClassOf: organizationalUnit
1289 self.ldb.add_ldif(ldif)
1291 # Search for created objectclass
1293 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
1294 attrs=["lDAPDisplayName", "defaultObjectCategory",
1295 "schemaIDGUID", "distinguishedName"])
1296 self.assertEquals(len(res), 1)
1297 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
1298 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
1299 self.assertTrue("schemaIDGUID" in res[0])
1304 add: schemaUpdateNow
1307 self.ldb.modify_ldif(ldif)
1309 object_name = "org" + time.strftime("%s", time.gmtime())
1312 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
1313 objectClass: """ + class_ldap_display_name + """
1314 ou: """ + object_name + """
1317 self.ldb.add_ldif(ldif)
1319 # Search for created object
1321 res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
1322 self.assertEquals(len(res), 1)
1324 delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
1327 class SchemaTests_msDS_IntId(samba.tests.TestCase):
1330 super(SchemaTests_msDS_IntId, self).setUp()
1331 self.ldb = SamDB(host, credentials=creds,
1332 session_info=system_session(lp), lp=lp, options=ldb_options)
1333 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
1334 attrs=["schemaNamingContext", "defaultNamingContext",
1335 "forestFunctionality"])
1336 self.assertEquals(len(res), 1)
1337 self.schema_dn = res[0]["schemaNamingContext"][0]
1338 self.base_dn = res[0]["defaultNamingContext"][0]
1339 self.forest_level = int(res[0]["forestFunctionality"][0])
1341 def _ldap_schemaUpdateNow(self):
1345 add: schemaUpdateNow
1348 self.ldb.modify_ldif(ldif)
1350 def _make_obj_names(self, prefix):
1351 class_name = prefix + time.strftime("%s", time.gmtime())
1352 class_ldap_name = class_name.replace("-", "")
1353 class_dn = "CN=%s,%s" % (class_name, self.schema_dn)
1354 return (class_name, class_ldap_name, class_dn)
1356 def _is_schema_base_object(self, ldb_msg):
1357 """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)"""
1359 if "systemFlags" in ldb_msg:
1360 systemFlags = int(ldb_msg["systemFlags"][0])
1361 return (systemFlags & 16) != 0
1363 def _make_attr_ldif(self, attr_name, attr_dn):
1365 dn: """ + attr_dn + """
1367 objectClass: attributeSchema
1368 adminDescription: """ + attr_name + """
1369 adminDisplayName: """ + attr_name + """
1370 cn: """ + attr_name + """
1371 attributeId: 1.3.6.1.4.1.7165.4.6.1.6.14.""" + str(random.randint(1, 100000)) + """
1372 attributeSyntax: 2.5.5.12
1375 isSingleValued: TRUE
1380 def test_msDS_IntId_on_attr(self):
1381 """Testing msDs-IntId creation for Attributes.
1382 See MS-ADTS - 3.1.1.Attributes
1384 This test should verify that:
1385 - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM
1386 - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION
1387 - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag
1388 set fails with ERR_UNWILLING_TO_PERFORM
1389 - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have
1390 'msDS-IntId' attribute added internally
1393 # 1. Create attribute without systemFlags
1394 # msDS-IntId should be created if forest functional
1395 # level is >= DS_DOMAIN_FUNCTION_2003
1396 # and missing otherwise
1397 (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-")
1398 ldif = self._make_attr_ldif(attr_name, attr_dn)
1400 # try to add msDS-IntId during Attribute creation
1401 ldif_fail = ldif + "msDS-IntId: -1993108831\n"
1403 self.ldb.add_ldif(ldif_fail)
1404 self.fail("Adding attribute with preset msDS-IntId should fail")
1405 except LdbError as e25:
1407 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1409 # add the new attribute and update schema
1410 self.ldb.add_ldif(ldif)
1411 self._ldap_schemaUpdateNow()
1413 # Search for created attribute
1415 res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
1416 attrs=["lDAPDisplayName", "msDS-IntId", "systemFlags"])
1417 self.assertEquals(len(res), 1)
1418 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
1419 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1420 if self._is_schema_base_object(res[0]):
1421 self.assertTrue("msDS-IntId" not in res[0])
1423 self.assertTrue("msDS-IntId" in res[0])
1425 self.assertTrue("msDS-IntId" not in res[0])
1428 msg.dn = Dn(self.ldb, attr_dn)
1429 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1431 self.ldb.modify(msg)
1432 self.fail("Modifying msDS-IntId should return error")
1433 except LdbError as e26:
1435 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1437 # 2. Create attribute with systemFlags = FLAG_SCHEMA_BASE_OBJECT
1438 # msDS-IntId should be created if forest functional
1439 # level is >= DS_DOMAIN_FUNCTION_2003
1440 # and missing otherwise
1441 (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-2-")
1442 ldif = self._make_attr_ldif(attr_name, attr_dn)
1443 ldif += "systemFlags: 16\n"
1445 # try to add msDS-IntId during Attribute creation
1446 ldif_fail = ldif + "msDS-IntId: -1993108831\n"
1448 self.ldb.add_ldif(ldif_fail)
1449 self.fail("Adding attribute with preset msDS-IntId should fail")
1450 except LdbError as e27:
1452 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1454 # add the new attribute and update schema
1455 self.ldb.add_ldif(ldif)
1456 self._ldap_schemaUpdateNow()
1458 # Search for created attribute
1460 res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
1461 attrs=["lDAPDisplayName", "msDS-IntId"])
1462 self.assertEquals(len(res), 1)
1463 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
1464 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1465 if self._is_schema_base_object(res[0]):
1466 self.assertTrue("msDS-IntId" not in res[0])
1468 self.assertTrue("msDS-IntId" in res[0])
1470 self.assertTrue("msDS-IntId" not in res[0])
1473 msg.dn = Dn(self.ldb, attr_dn)
1474 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1476 self.ldb.modify(msg)
1477 self.fail("Modifying msDS-IntId should return error")
1478 except LdbError as e28:
1480 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1482 def _make_class_ldif(self, class_dn, class_name, sub_oid):
1484 dn: """ + class_dn + """
1486 objectClass: classSchema
1487 adminDescription: """ + class_name + """
1488 adminDisplayName: """ + class_name + """
1489 cn: """ + class_name + """
1490 governsId: 1.3.6.1.4.1.7165.4.6.2.6.%d.""" % sub_oid + str(random.randint(1, 100000)) + """
1492 objectClassCategory: 1
1493 subClassOf: organizationalPerson
1495 systemMustContain: cn
1500 def test_msDS_IntId_on_class(self):
1501 """Testing msDs-IntId creation for Class
1502 Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema"""
1504 # 1. Create Class without systemFlags
1505 # msDS-IntId should be created if forest functional
1506 # level is >= DS_DOMAIN_FUNCTION_2003
1507 # and missing otherwise
1508 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-")
1509 ldif = self._make_class_ldif(class_dn, class_name, 8)
1511 # try to add msDS-IntId during Class creation
1512 ldif_add = ldif + "msDS-IntId: -1993108831\n"
1513 self.ldb.add_ldif(ldif_add)
1514 self._ldap_schemaUpdateNow()
1516 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1517 self.assertEquals(len(res), 1)
1518 self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
1520 # add a new Class and update schema
1521 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-")
1522 ldif = self._make_class_ldif(class_dn, class_name, 9)
1524 self.ldb.add_ldif(ldif)
1525 self._ldap_schemaUpdateNow()
1527 # Search for created Class
1528 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1529 self.assertEquals(len(res), 1)
1530 self.assertFalse("msDS-IntId" in res[0])
1533 msg.dn = Dn(self.ldb, class_dn)
1534 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1536 self.ldb.modify(msg)
1537 self.fail("Modifying msDS-IntId should return error")
1538 except LdbError as e29:
1540 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1542 # 2. Create Class with systemFlags = FLAG_SCHEMA_BASE_OBJECT
1543 # msDS-IntId should be created if forest functional
1544 # level is >= DS_DOMAIN_FUNCTION_2003
1545 # and missing otherwise
1546 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-3-")
1547 ldif = self._make_class_ldif(class_dn, class_name, 10)
1548 ldif += "systemFlags: 16\n"
1550 # try to add msDS-IntId during Class creation
1551 ldif_add = ldif + "msDS-IntId: -1993108831\n"
1552 self.ldb.add_ldif(ldif_add)
1554 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1555 self.assertEquals(len(res), 1)
1556 self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
1558 # add the new Class and update schema
1559 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-4-")
1560 ldif = self._make_class_ldif(class_dn, class_name, 11)
1561 ldif += "systemFlags: 16\n"
1563 self.ldb.add_ldif(ldif)
1564 self._ldap_schemaUpdateNow()
1566 # Search for created Class
1567 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1568 self.assertEquals(len(res), 1)
1569 self.assertFalse("msDS-IntId" in res[0])
1572 msg.dn = Dn(self.ldb, class_dn)
1573 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1575 self.ldb.modify(msg)
1576 self.fail("Modifying msDS-IntId should return error")
1577 except LdbError as e30:
1579 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1580 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1581 self.assertEquals(len(res), 1)
1582 self.assertFalse("msDS-IntId" in res[0])
1584 def test_verify_msDS_IntId(self):
1585 """Verify msDS-IntId exists only on attributes without FLAG_SCHEMA_BASE_OBJECT flag set"""
1587 res = self.ldb.search(self.schema_dn, scope=SCOPE_ONELEVEL,
1588 expression="objectClass=attributeSchema",
1589 attrs=["systemFlags", "msDS-IntId", "attributeID", "cn"])
1590 self.assertTrue(len(res) > 1)
1592 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1593 if self._is_schema_base_object(ldb_msg):
1594 self.assertTrue("msDS-IntId" not in ldb_msg)
1596 # don't assert here as there are plenty of
1597 # attributes under w2k8 that are not part of
1598 # Base Schema (SYSTEM_FLAG_SCHEMA_BASE_OBJECT flag not set)
1599 # has not msDS-IntId attribute set
1600 #self.assertTrue("msDS-IntId" in ldb_msg, "msDS-IntId expected on: %s" % ldb_msg.dn)
1601 if "msDS-IntId" not in ldb_msg:
1603 print("%3d warning: msDS-IntId expected on: %-30s %s" % (count, ldb_msg["attributeID"], ldb_msg["cn"]))
1605 self.assertTrue("msDS-IntId" not in ldb_msg)
1608 class SchemaTests_msDS_isRODC(samba.tests.TestCase):
1611 super(SchemaTests_msDS_isRODC, self).setUp()
1612 self.ldb = SamDB(host, credentials=creds,
1613 session_info=system_session(lp), lp=lp, options=ldb_options)
1614 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["defaultNamingContext"])
1615 self.assertEquals(len(res), 1)
1616 self.base_dn = res[0]["defaultNamingContext"][0]
1618 def test_objectClass_ntdsdsa(self):
1619 res = self.ldb.search(self.base_dn, expression="objectClass=nTDSDSA",
1620 attrs=["msDS-isRODC"], controls=["search_options:1:2"])
1622 self.assertTrue("msDS-isRODC" in ldb_msg)
1624 def test_objectClass_server(self):
1625 res = self.ldb.search(self.base_dn, expression="objectClass=server",
1626 attrs=["msDS-isRODC"], controls=["search_options:1:2"])
1628 ntds_search_dn = "CN=NTDS Settings,%s" % ldb_msg['dn']
1630 res_check = self.ldb.search(ntds_search_dn, attrs=["objectCategory"])
1631 except LdbError as e:
1633 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1634 print("Server entry %s doesn't have a NTDS settings object" % res[0]['dn'])
1636 self.assertTrue("objectCategory" in res_check[0])
1637 self.assertTrue("msDS-isRODC" in ldb_msg)
1639 def test_objectClass_computer(self):
1640 res = self.ldb.search(self.base_dn, expression="objectClass=computer",
1641 attrs=["serverReferenceBL", "msDS-isRODC"], controls=["search_options:1:2"])
1643 if "serverReferenceBL" not in ldb_msg:
1644 print("Computer entry %s doesn't have a serverReferenceBL attribute" % ldb_msg['dn'])
1646 self.assertTrue("msDS-isRODC" in ldb_msg)
1649 if "://" not in host:
1650 if os.path.isfile(host):
1651 host = "tdb://%s" % host
1653 host = "ldap://%s" % host
1656 if host.startswith("ldap://"):
1657 # user 'paged_search' module when connecting remotely
1658 ldb_options = ["modules:paged_searches"]
1660 TestProgram(module=__name__, opts=subunitopts)