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/>.
23 from __future__ import print_function
30 sys.path.insert(0, "bin/python")
32 from samba.tests.subunitrun import TestProgram, SubunitOptions
34 import samba.getopt as options
36 from samba.auth import system_session
37 from ldb import SCOPE_ONELEVEL, SCOPE_BASE, LdbError
38 from ldb import ERR_NO_SUCH_OBJECT
39 from ldb import ERR_UNWILLING_TO_PERFORM
40 from ldb import ERR_ENTRY_ALREADY_EXISTS
41 from ldb import ERR_CONSTRAINT_VIOLATION
42 from ldb import ERR_OBJECT_CLASS_VIOLATION
43 from ldb import Message, MessageElement, Dn
44 from ldb import FLAG_MOD_REPLACE
45 from samba.samdb import SamDB
46 from samba.dsdb import DS_DOMAIN_FUNCTION_2003
47 from samba.tests import delete_force
48 from samba.ndr import ndr_unpack
49 from samba.dcerpc import drsblobs
51 parser = optparse.OptionParser("ldap_schema.py [options] <host>")
52 sambaopts = options.SambaOptions(parser)
53 parser.add_option_group(sambaopts)
54 parser.add_option_group(options.VersionOptions(parser))
55 # use command line creds if available
56 credopts = options.CredentialsOptions(parser)
57 parser.add_option_group(credopts)
58 subunitopts = SubunitOptions(parser)
59 parser.add_option_group(subunitopts)
60 opts, args = parser.parse_args()
68 lp = sambaopts.get_loadparm()
69 creds = credopts.get_credentials(lp)
72 class SchemaTests(samba.tests.TestCase):
75 super(SchemaTests, self).setUp()
76 self.ldb = SamDB(host, credentials=creds,
77 session_info=system_session(lp), lp=lp, options=ldb_options)
78 self.base_dn = self.ldb.domain_dn()
79 self.schema_dn = self.ldb.get_schema_basedn().get_linearized()
81 def test_generated_schema(self):
82 """Testing we can read the generated schema via LDAP"""
83 res = self.ldb.search("cn=aggregate," + self.schema_dn, scope=SCOPE_BASE,
84 attrs=["objectClasses", "attributeTypes", "dITContentRules"])
85 self.assertEquals(len(res), 1)
86 self.assertTrue("dITContentRules" in res[0])
87 self.assertTrue("objectClasses" in res[0])
88 self.assertTrue("attributeTypes" in res[0])
90 def test_generated_schema_is_operational(self):
91 """Testing we don't get the generated schema via LDAP by default"""
92 # Must keep the "*" form
93 res = self.ldb.search("cn=aggregate," + self.schema_dn, scope=SCOPE_BASE,
95 self.assertEquals(len(res), 1)
96 self.assertFalse("dITContentRules" in res[0])
97 self.assertFalse("objectClasses" in res[0])
98 self.assertFalse("attributeTypes" in res[0])
100 def test_schemaUpdateNow(self):
101 """Testing schemaUpdateNow"""
102 rand = str(random.randint(1, 100000))
103 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
104 attr_ldap_display_name = attr_name.replace("-", "")
107 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
109 objectClass: attributeSchema
110 adminDescription: """ + attr_name + """
111 adminDisplayName: """ + attr_name + """
112 cn: """ + attr_name + """
113 attributeId: 1.3.6.1.4.1.7165.4.6.1.6.1.""" + rand + """
114 attributeSyntax: 2.5.5.12
120 self.ldb.add_ldif(ldif)
121 # We must do a schemaUpdateNow otherwise it's not 100% sure that the schema
122 # will contain the new attribute
129 self.ldb.modify_ldif(ldif)
131 # Search for created attribute
133 res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE,
134 attrs=["lDAPDisplayName", "schemaIDGUID", "msDS-IntID"])
135 self.assertEquals(len(res), 1)
136 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
137 self.assertTrue("schemaIDGUID" in res[0])
138 if "msDS-IntId" in res[0]:
139 msDS_IntId = int(res[0]["msDS-IntId"][0])
141 msDS_IntId += (1 << 32)
145 class_name = "test-Class" + time.strftime("%s", time.gmtime())
146 class_ldap_display_name = class_name.replace("-", "")
148 # First try to create a class with a wrong "defaultObjectCategory"
150 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
152 objectClass: classSchema
153 defaultObjectCategory: CN=_
154 adminDescription: """ + class_name + """
155 adminDisplayName: """ + class_name + """
156 cn: """ + class_name + """
157 governsId: 1.3.6.1.4.1.7165.4.6.2.6.1.""" + str(random.randint(1, 100000)) + """
159 objectClassCategory: 1
160 subClassOf: organizationalPerson
163 systemMustContain: cn
164 systemMustContain: """ + attr_ldap_display_name + """
168 self.ldb.add_ldif(ldif)
170 except LdbError as e1:
172 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
175 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
177 objectClass: classSchema
178 adminDescription: """ + class_name + """
179 adminDisplayName: """ + class_name + """
180 cn: """ + class_name + """
181 governsId: 1.3.6.1.4.1.7165.4.6.2.6.2.""" + str(random.randint(1, 100000)) + """
183 objectClassCategory: 1
184 subClassOf: organizationalPerson
187 systemMustContain: cn
188 systemMustContain: """ + attr_ldap_display_name + """
191 self.ldb.add_ldif(ldif)
193 # Search for created objectclass
195 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
196 attrs=["lDAPDisplayName", "defaultObjectCategory", "schemaIDGUID", "distinguishedName"])
197 self.assertEquals(len(res), 1)
198 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
199 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
200 self.assertTrue("schemaIDGUID" in res[0])
208 self.ldb.modify_ldif(ldif)
210 object_name = "obj" + time.strftime("%s", time.gmtime())
213 dn: CN=%s,CN=Users,%s""" % (object_name, self.base_dn) + """
214 objectClass: organizationalPerson
216 objectClass: """ + class_ldap_display_name + """
218 cn: """ + object_name + """
220 objectCategory: CN=%s,%s""" % (class_name, self.schema_dn) + """
221 distinguishedName: CN=%s,CN=Users,%s""" % (object_name, self.base_dn) + """
222 name: """ + object_name + """
223 """ + attr_ldap_display_name + """: test
225 self.ldb.add_ldif(ldif)
227 # Search for created object
228 obj_res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["replPropertyMetaData"])
230 self.assertEquals(len(obj_res), 1)
231 self.assertTrue("replPropertyMetaData" in obj_res[0])
232 val = obj_res[0]["replPropertyMetaData"][0]
233 repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
236 # Windows 2000 functional level won't have this. It is too
237 # hard to work it out from the prefixmap however, so we skip
238 # this test in that case.
239 if msDS_IntId is not None:
241 for o in repl.ctr.array:
242 if o.attid == msDS_IntId:
245 self.assertTrue(found, "Did not find 0x%08x in replPropertyMetaData" % msDS_IntId)
247 delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
249 def test_subClassOf(self):
250 """ Testing usage of custom child schamaClass
253 class_name = "my-Class" + time.strftime("%s", time.gmtime())
254 class_ldap_display_name = class_name.replace("-", "")
257 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
259 objectClass: classSchema
260 adminDescription: """ + class_name + """
261 adminDisplayName: """ + class_name + """
262 cn: """ + class_name + """
263 governsId: 1.3.6.1.4.1.7165.4.6.2.6.3.""" + str(random.randint(1, 100000)) + """
265 objectClassCategory: 1
266 subClassOf: organizationalUnit
270 self.ldb.add_ldif(ldif)
272 # Search for created objectclass
274 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
275 attrs=["lDAPDisplayName", "defaultObjectCategory",
276 "schemaIDGUID", "distinguishedName"])
277 self.assertEquals(len(res), 1)
278 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
279 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
280 self.assertTrue("schemaIDGUID" in res[0])
288 self.ldb.modify_ldif(ldif)
290 object_name = "org" + time.strftime("%s", time.gmtime())
293 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
294 objectClass: """ + class_ldap_display_name + """
295 ou: """ + object_name + """
298 self.ldb.add_ldif(ldif)
300 # Search for created object
302 res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
303 self.assertEquals(len(res), 1)
305 delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
308 def test_duplicate_attributeID(self):
309 """Testing creating a duplicate attribute"""
310 rand = str(random.randint(1, 100000))
311 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
312 attr_ldap_display_name = attr_name.replace("-", "")
313 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.2." + rand
315 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
317 objectClass: attributeSchema
318 adminDescription: """ + attr_name + """
319 adminDisplayName: """ + attr_name + """
320 cn: """ + attr_name + """
321 attributeId: """ + attributeID + """
322 attributeSyntax: 2.5.5.12
328 self.ldb.add_ldif(ldif)
331 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
333 objectClass: attributeSchema
334 adminDescription: """ + attr_name + """dup
335 adminDisplayName: """ + attr_name + """dup
336 cn: """ + attr_name + """-dup
337 attributeId: """ + attributeID + """
338 attributeSyntax: 2.5.5.12
345 self.ldb.add_ldif(ldif)
346 self.fail("Should have failed to add duplicate attributeID value")
347 except LdbError as e2:
348 (enum, estr) = e2.args
349 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
352 def test_duplicate_attributeID_governsID(self):
353 """Testing creating a duplicate attribute and class"""
354 rand = str(random.randint(1, 100000))
355 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
356 attr_ldap_display_name = attr_name.replace("-", "")
357 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.3." + rand
359 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
361 objectClass: attributeSchema
362 adminDescription: """ + attr_name + """
363 adminDisplayName: """ + attr_name + """
364 cn: """ + attr_name + """
365 attributeId: """ + attributeID + """
366 attributeSyntax: 2.5.5.12
372 self.ldb.add_ldif(ldif)
375 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
377 objectClass: classSchema
378 adminDescription: """ + attr_name + """dup
379 adminDisplayName: """ + attr_name + """dup
380 cn: """ + attr_name + """-dup
381 governsId: """ + attributeID + """
383 objectClassCategory: 1
384 subClassOf: organizationalPerson
386 systemMustContain: cn
390 self.ldb.add_ldif(ldif)
391 self.fail("Should have failed to add duplicate governsID conflicting with attributeID value")
392 except LdbError as e3:
393 (enum, estr) = e3.args
394 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
397 def test_duplicate_cn(self):
398 """Testing creating a duplicate attribute"""
399 rand = str(random.randint(1, 100000))
400 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
401 attr_ldap_display_name = attr_name.replace("-", "")
402 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.4." + rand
404 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
406 objectClass: attributeSchema
407 adminDescription: """ + attr_name + """
408 adminDisplayName: """ + attr_name + """
409 cn: """ + attr_name + """
410 attributeId: """ + attributeID + """
411 attributeSyntax: 2.5.5.12
417 self.ldb.add_ldif(ldif)
420 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
422 objectClass: attributeSchema
423 adminDescription: """ + attr_name + """dup
424 adminDisplayName: """ + attr_name + """dup
425 cn: """ + attr_name + """
426 attributeId: """ + attributeID + """.1
427 attributeSyntax: 2.5.5.12
434 self.ldb.add_ldif(ldif)
435 self.fail("Should have failed to add attribute with duplicate CN")
436 except LdbError as e4:
437 (enum, estr) = e4.args
438 self.assertEquals(enum, ERR_ENTRY_ALREADY_EXISTS)
440 def test_duplicate_implicit_ldapdisplayname(self):
441 """Testing creating a duplicate attribute ldapdisplayname"""
442 rand = str(random.randint(1, 100000))
443 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
444 attr_ldap_display_name = attr_name.replace("-", "")
445 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.5." + rand
447 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
449 objectClass: attributeSchema
450 adminDescription: """ + attr_name + """
451 adminDisplayName: """ + attr_name + """
452 cn: """ + attr_name + """
453 attributeId: """ + attributeID + """
454 attributeSyntax: 2.5.5.12
460 self.ldb.add_ldif(ldif)
463 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
465 objectClass: attributeSchema
466 adminDescription: """ + attr_name + """dup
467 adminDisplayName: """ + attr_name + """dup
468 cn: """ + attr_name + """-dup
469 ldapDisplayName: """ + attr_ldap_display_name + """
470 attributeId: """ + attributeID + """.1
471 attributeSyntax: 2.5.5.12
478 self.ldb.add_ldif(ldif)
479 self.fail("Should have failed to add attribute with duplicate of the implicit ldapDisplayName")
480 except LdbError as e5:
481 (enum, estr) = e5.args
482 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
485 def test_duplicate_explicit_ldapdisplayname(self):
486 """Testing creating a duplicate attribute ldapdisplayname"""
487 rand = str(random.randint(1, 100000))
488 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
489 attr_ldap_display_name = attr_name.replace("-", "")
490 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.6." + rand
492 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
494 objectClass: attributeSchema
495 adminDescription: """ + attr_name + """
496 adminDisplayName: """ + attr_name + """
497 cn: """ + attr_name + """
498 attributeId: """ + attributeID + """
499 attributeSyntax: 2.5.5.12
500 ldapDisplayName: """ + attr_ldap_display_name + """
506 self.ldb.add_ldif(ldif)
509 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
511 objectClass: attributeSchema
512 adminDescription: """ + attr_name + """dup
513 adminDisplayName: """ + attr_name + """dup
514 cn: """ + attr_name + """-dup
515 ldapDisplayName: """ + attr_ldap_display_name + """
516 attributeId: """ + attributeID + """.1
517 attributeSyntax: 2.5.5.12
524 self.ldb.add_ldif(ldif)
525 self.fail("Should have failed to add attribute with duplicate ldapDisplayName")
526 except LdbError as e6:
527 (enum, estr) = e6.args
528 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
531 def test_duplicate_explicit_ldapdisplayname_with_class(self):
532 """Testing creating a duplicate attribute ldapdisplayname between
533 and attribute and a class"""
534 rand = str(random.randint(1, 100000))
535 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
536 attr_ldap_display_name = attr_name.replace("-", "")
537 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.7." + rand
538 governsID = "1.3.6.1.4.1.7165.4.6.2.6.4." + rand
540 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
542 objectClass: attributeSchema
543 adminDescription: """ + attr_name + """
544 adminDisplayName: """ + attr_name + """
545 cn: """ + attr_name + """
546 attributeId: """ + attributeID + """
547 attributeSyntax: 2.5.5.12
548 ldapDisplayName: """ + attr_ldap_display_name + """
554 self.ldb.add_ldif(ldif)
557 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
559 objectClass: classSchema
560 adminDescription: """ + attr_name + """dup
561 adminDisplayName: """ + attr_name + """dup
562 cn: """ + attr_name + """-dup
563 ldapDisplayName: """ + attr_ldap_display_name + """
564 governsID: """ + governsID + """
566 objectClassCategory: 1
567 subClassOf: organizationalPerson
569 systemMustContain: cn
573 self.ldb.add_ldif(ldif)
574 self.fail("Should have failed to add class with duplicate ldapDisplayName")
575 except LdbError as e7:
576 (enum, estr) = e7.args
577 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
580 def test_duplicate_via_rename_ldapdisplayname(self):
581 """Testing creating a duplicate attribute ldapdisplayname"""
582 rand = str(random.randint(1, 100000))
583 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
584 attr_ldap_display_name = attr_name.replace("-", "")
585 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.8." + rand
587 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
589 objectClass: attributeSchema
590 adminDescription: """ + attr_name + """
591 adminDisplayName: """ + attr_name + """
592 cn: """ + attr_name + """
593 attributeId: """ + attributeID + """
594 attributeSyntax: 2.5.5.12
595 ldapDisplayName: """ + attr_ldap_display_name + """
601 self.ldb.add_ldif(ldif)
604 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
606 objectClass: attributeSchema
607 adminDescription: """ + attr_name + """dup
608 adminDisplayName: """ + attr_name + """dup
609 cn: """ + attr_name + """-dup
610 ldapDisplayName: """ + attr_ldap_display_name + """dup
611 attributeId: """ + attributeID + """.1
612 attributeSyntax: 2.5.5.12
618 self.ldb.add_ldif(ldif)
621 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
623 replace: ldapDisplayName
624 ldapDisplayName: """ + attr_ldap_display_name + """
628 self.ldb.modify_ldif(ldif)
629 self.fail("Should have failed to modify schema to have attribute with duplicate ldapDisplayName")
630 except LdbError as e8:
631 (enum, estr) = e8.args
632 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
635 def test_duplicate_via_rename_attributeID(self):
636 """Testing creating a duplicate attributeID"""
637 rand = str(random.randint(1, 100000))
638 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
639 attr_ldap_display_name = attr_name.replace("-", "")
640 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.9." + rand
642 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
644 objectClass: attributeSchema
645 adminDescription: """ + attr_name + """
646 adminDisplayName: """ + attr_name + """
647 cn: """ + attr_name + """
648 attributeId: """ + attributeID + """
649 attributeSyntax: 2.5.5.12
650 ldapDisplayName: """ + attr_ldap_display_name + """
656 self.ldb.add_ldif(ldif)
659 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
661 objectClass: attributeSchema
662 adminDescription: """ + attr_name + """dup
663 adminDisplayName: """ + attr_name + """dup
664 cn: """ + attr_name + """-dup
665 ldapDisplayName: """ + attr_ldap_display_name + """dup
666 attributeId: """ + attributeID + """.1
667 attributeSyntax: 2.5.5.12
673 self.ldb.add_ldif(ldif)
676 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
679 attributeId: """ + attributeID + """
683 self.ldb.modify_ldif(ldif)
684 self.fail("Should have failed to modify schema to have attribute with duplicate attributeID")
685 except LdbError as e9:
686 (enum, estr) = e9.args
687 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
689 def test_remove_ldapdisplayname(self):
690 """Testing removing the ldapdisplayname"""
691 rand = str(random.randint(1, 100000))
692 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
693 attr_ldap_display_name = attr_name.replace("-", "")
694 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.10." + rand
696 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
698 objectClass: attributeSchema
699 adminDescription: """ + attr_name + """
700 adminDisplayName: """ + attr_name + """
701 cn: """ + attr_name + """
702 attributeId: """ + attributeID + """
703 attributeSyntax: 2.5.5.12
704 ldapDisplayName: """ + attr_ldap_display_name + """
710 self.ldb.add_ldif(ldif)
713 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
715 replace: ldapDisplayName
719 self.ldb.modify_ldif(ldif)
720 self.fail("Should have failed to remove the ldapdisplayname")
721 except LdbError as e10:
722 (enum, estr) = e10.args
723 self.assertEquals(enum, ERR_OBJECT_CLASS_VIOLATION)
725 def test_rename_ldapdisplayname(self):
726 """Testing renaming ldapdisplayname"""
727 rand = str(random.randint(1, 100000))
728 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
729 attr_ldap_display_name = attr_name.replace("-", "")
730 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.11." + rand
732 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
734 objectClass: attributeSchema
735 adminDescription: """ + attr_name + """
736 adminDisplayName: """ + attr_name + """
737 cn: """ + attr_name + """
738 attributeId: """ + attributeID + """
739 attributeSyntax: 2.5.5.12
740 ldapDisplayName: """ + attr_ldap_display_name + """
746 self.ldb.add_ldif(ldif)
749 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
751 replace: ldapDisplayName
752 ldapDisplayName: """ + attr_ldap_display_name + """2
755 self.ldb.modify_ldif(ldif)
758 def test_change_attributeID(self):
759 """Testing change the attributeID"""
760 rand = str(random.randint(1, 100000))
761 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
762 attr_ldap_display_name = attr_name.replace("-", "")
763 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.12." + rand
765 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
767 objectClass: attributeSchema
768 adminDescription: """ + attr_name + """
769 adminDisplayName: """ + attr_name + """
770 cn: """ + attr_name + """
771 attributeId: """ + attributeID + """
772 attributeSyntax: 2.5.5.12
773 ldapDisplayName: """ + attr_ldap_display_name + """
779 self.ldb.add_ldif(ldif)
782 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
785 attributeId: """ + attributeID + """.1
789 self.ldb.modify_ldif(ldif)
790 self.fail("Should have failed to modify schema to have different attributeID")
791 except LdbError as e11:
792 (enum, estr) = e11.args
793 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
796 def test_change_attributeID_same(self):
797 """Testing change the attributeID to the same value"""
798 rand = str(random.randint(1, 100000))
799 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
800 attr_ldap_display_name = attr_name.replace("-", "")
801 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.13." + rand
803 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
805 objectClass: attributeSchema
806 adminDescription: """ + attr_name + """
807 adminDisplayName: """ + attr_name + """
808 cn: """ + attr_name + """
809 attributeId: """ + attributeID + """
810 attributeSyntax: 2.5.5.12
811 ldapDisplayName: """ + attr_ldap_display_name + """
817 self.ldb.add_ldif(ldif)
820 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
823 attributeId: """ + attributeID + """
827 self.ldb.modify_ldif(ldif)
828 self.fail("Should have failed to modify schema to have the same attributeID")
829 except LdbError as e12:
830 (enum, estr) = e12.args
831 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
834 def test_generated_linkID(self):
836 Test that we automatically generate a linkID if the
837 OID "1.2.840.113556.1.2.50" is given as the linkID
838 of a new attribute, and that we don't get/can't add
839 duplicate linkIDs. Also test that we can add a backlink
840 by providing the attributeID or ldapDisplayName of
841 a forwards link in the linkID attribute.
844 # linkID generation isn't available before 2003
845 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
846 attrs=["domainControllerFunctionality"])
847 self.assertEquals(len(res), 1)
848 dc_level = int(res[0]["domainControllerFunctionality"][0])
849 if dc_level < DS_DOMAIN_FUNCTION_2003:
852 rand = str(random.randint(1, 100000))
854 attr_name_1 = "test-generated-linkID" + time.strftime("%s", time.gmtime()) + "-" + rand
855 attr_ldap_display_name_1 = attr_name_1.replace("-", "")
856 attributeID_1 = "1.3.6.1.4.1.7165.4.6.1.6.16." + rand
858 dn: CN=%s,%s""" % (attr_name_1, self.schema_dn) + """
860 objectClass: attributeSchema
861 adminDescription: """ + attr_name_1 + """
862 adminDisplayName: """ + attr_name_1 + """
863 cn: """ + attr_name_1 + """
864 attributeId: """ + attributeID_1 + """
865 linkID: 1.2.840.113556.1.2.50
866 attributeSyntax: 2.5.5.1
867 ldapDisplayName: """ + attr_ldap_display_name_1 + """
875 self.ldb.add_ldif(ldif)
876 except LdbError as e13:
877 (enum, estr) = e13.args
880 attr_name_2 = "test-generated-linkID-2" + time.strftime("%s", time.gmtime()) + "-" + rand
881 attr_ldap_display_name_2 = attr_name_2.replace("-", "")
882 attributeID_2 = "1.3.6.1.4.1.7165.4.6.1.6.17." + rand
884 dn: CN=%s,%s""" % (attr_name_2, self.schema_dn) + """
886 objectClass: attributeSchema
887 adminDescription: """ + attr_name_2 + """
888 adminDisplayName: """ + attr_name_2 + """
889 cn: """ + attr_name_2 + """
890 attributeId: """ + attributeID_2 + """
891 linkID: 1.2.840.113556.1.2.50
892 attributeSyntax: 2.5.5.1
893 ldapDisplayName: """ + attr_ldap_display_name_2 + """
901 self.ldb.add_ldif(ldif)
902 except LdbError as e14:
903 (enum, estr) = e14.args
906 res = self.ldb.search("CN=%s,%s" % (attr_name_1, self.schema_dn),
909 self.assertEquals(len(res), 1)
910 linkID_1 = int(res[0]["linkID"][0])
912 res = self.ldb.search("CN=%s,%s" % (attr_name_2, self.schema_dn),
915 self.assertEquals(len(res), 1)
916 linkID_2 = int(res[0]["linkID"][0])
918 # 0 should never be generated as a linkID
919 self.assertFalse(linkID_1 == 0)
920 self.assertFalse(linkID_2 == 0)
922 # The generated linkID should always be even, because
923 # it should assume we're adding a forward link.
924 self.assertTrue(linkID_1 % 2 == 0)
925 self.assertTrue(linkID_2 % 2 == 0)
927 self.assertFalse(linkID_1 == linkID_2)
929 # This is only necessary against Windows, since we depend
930 # on the previously added links in the next ones and Windows
931 # won't refresh the schema as we add them.
935 replace: schemaupdatenow
938 self.ldb.modify_ldif(ldif)
940 # If we add a new link with the same linkID, it should fail
941 attr_name = "test-generated-linkID-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
942 attr_ldap_display_name = attr_name.replace("-", "")
943 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.18." + rand
945 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
947 objectClass: attributeSchema
948 adminDescription: """ + attr_name + """
949 adminDisplayName: """ + attr_name + """
950 cn: """ + attr_name + """
951 attributeId: """ + attributeID + """
952 linkID: """ + str(linkID_1) + """
953 attributeSyntax: 2.5.5.1
954 ldapDisplayName: """ + attr_ldap_display_name + """
962 self.ldb.add_ldif(ldif)
963 self.fail("Should have failed to add duplicate linkID value")
964 except LdbError as e15:
965 (enum, estr) = e15.args
966 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
968 # If we add another attribute with the attributeID or lDAPDisplayName
969 # of a forward link in its linkID field, it should add as a backlink
971 attr_name_3 = "test-generated-linkID-backlink" + time.strftime("%s", time.gmtime()) + "-" + rand
972 attr_ldap_display_name_3 = attr_name_3.replace("-", "")
973 attributeID_3 = "1.3.6.1.4.1.7165.4.6.1.6.19." + rand
975 dn: CN=%s,%s""" % (attr_name_3, self.schema_dn) + """
977 objectClass: attributeSchema
978 adminDescription: """ + attr_name_3 + """
979 adminDisplayName: """ + attr_name_3 + """
980 cn: """ + attr_name_3 + """
981 attributeId: """ + attributeID_3 + """
982 linkID: """ + str(linkID_1 + 1) + """
983 attributeSyntax: 2.5.5.1
984 ldapDisplayName: """ + attr_ldap_display_name_3 + """
992 self.ldb.add_ldif(ldif)
993 except LdbError as e16:
994 (enum, estr) = e16.args
997 res = self.ldb.search("CN=%s,%s" % (attr_name_3, self.schema_dn),
1000 self.assertEquals(len(res), 1)
1001 linkID = int(res[0]["linkID"][0])
1002 self.assertEquals(linkID, linkID_1 + 1)
1004 attr_name_4 = "test-generated-linkID-backlink-2" + time.strftime("%s", time.gmtime()) + "-" + rand
1005 attr_ldap_display_name_4 = attr_name_4.replace("-", "")
1006 attributeID_4 = "1.3.6.1.4.1.7165.4.6.1.6.20." + rand
1008 dn: CN=%s,%s""" % (attr_name_4, self.schema_dn) + """
1010 objectClass: attributeSchema
1011 adminDescription: """ + attr_name_4 + """
1012 adminDisplayName: """ + attr_name_4 + """
1013 cn: """ + attr_name_4 + """
1014 attributeId: """ + attributeID_4 + """
1015 linkID: """ + attr_ldap_display_name_2 + """
1016 attributeSyntax: 2.5.5.1
1017 ldapDisplayName: """ + attr_ldap_display_name_4 + """
1020 isSingleValued: TRUE
1025 self.ldb.add_ldif(ldif)
1026 except LdbError as e17:
1027 (enum, estr) = e17.args
1030 res = self.ldb.search("CN=%s,%s" % (attr_name_4, self.schema_dn),
1033 self.assertEquals(len(res), 1)
1034 linkID = int(res[0]["linkID"][0])
1035 self.assertEquals(linkID, linkID_2 + 1)
1037 # If we then try to add another backlink in the same way
1038 # for the same forwards link, we should fail.
1040 attr_name = "test-generated-linkID-backlink-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
1041 attr_ldap_display_name = attr_name.replace("-", "")
1042 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.21." + rand
1044 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1046 objectClass: attributeSchema
1047 adminDescription: """ + attr_name + """
1048 adminDisplayName: """ + attr_name + """
1049 cn: """ + attr_name + """
1050 attributeId: """ + attributeID + """
1051 linkID: """ + attributeID_1 + """
1052 attributeSyntax: 2.5.5.1
1053 ldapDisplayName: """ + attr_ldap_display_name + """
1056 isSingleValued: TRUE
1061 self.ldb.add_ldif(ldif)
1062 self.fail("Should have failed to add duplicate backlink")
1063 except LdbError as e18:
1064 (enum, estr) = e18.args
1065 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1067 # If we try to supply the attributeID or ldapDisplayName
1068 # of an existing backlink in the linkID field of a new link,
1071 attr_name = "test-generated-linkID-backlink-invalid" + time.strftime("%s", time.gmtime()) + "-" + rand
1072 attr_ldap_display_name = attr_name.replace("-", "")
1073 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.22." + rand
1075 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1077 objectClass: attributeSchema
1078 adminDescription: """ + attr_name + """
1079 adminDisplayName: """ + attr_name + """
1080 cn: """ + attr_name + """
1081 attributeId: """ + attributeID + """
1082 linkID: """ + attributeID_3 + """
1083 attributeSyntax: 2.5.5.1
1084 ldapDisplayName: """ + attr_ldap_display_name + """
1087 isSingleValued: TRUE
1092 self.ldb.add_ldif(ldif)
1093 self.fail("Should have failed to add backlink of backlink")
1094 except LdbError as e19:
1095 (enum, estr) = e19.args
1096 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1098 attr_name = "test-generated-linkID-backlink-invalid-2" + time.strftime("%s", time.gmtime()) + "-" + rand
1099 attr_ldap_display_name = attr_name.replace("-", "")
1100 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.23." + rand
1102 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1104 objectClass: attributeSchema
1105 adminDescription: """ + attr_name + """
1106 adminDisplayName: """ + attr_name + """
1107 cn: """ + attr_name + """
1108 attributeId: """ + attributeID + """
1109 linkID: """ + attr_ldap_display_name_4 + """
1110 attributeSyntax: 2.5.5.1
1111 ldapDisplayName: """ + attr_ldap_display_name + """
1114 isSingleValued: TRUE
1119 self.ldb.add_ldif(ldif)
1120 self.fail("Should have failed to add backlink of backlink")
1121 except LdbError as e20:
1122 (enum, estr) = e20.args
1123 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1125 def test_generated_mAPIID(self):
1127 Test that we automatically generate a mAPIID if the
1128 OID "1.2.840.113556.1.2.49" is given as the mAPIID
1129 of a new attribute, and that we don't get/can't add
1133 rand = str(random.randint(1, 100000))
1135 attr_name_1 = "test-generated-mAPIID" + time.strftime("%s", time.gmtime()) + "-" + rand
1136 attr_ldap_display_name_1 = attr_name_1.replace("-", "")
1137 attributeID_1 = "1.3.6.1.4.1.7165.4.6.1.6.24." + rand
1139 dn: CN=%s,%s""" % (attr_name_1, self.schema_dn) + """
1141 objectClass: attributeSchema
1142 adminDescription: """ + attr_name_1 + """
1143 adminDisplayName: """ + attr_name_1 + """
1144 cn: """ + attr_name_1 + """
1145 attributeId: """ + attributeID_1 + """
1146 mAPIID: 1.2.840.113556.1.2.49
1147 attributeSyntax: 2.5.5.1
1148 ldapDisplayName: """ + attr_ldap_display_name_1 + """
1151 isSingleValued: TRUE
1156 self.ldb.add_ldif(ldif)
1157 except LdbError as e21:
1158 (enum, estr) = e21.args
1161 res = self.ldb.search("CN=%s,%s" % (attr_name_1, self.schema_dn),
1164 self.assertEquals(len(res), 1)
1165 mAPIID_1 = int(res[0]["mAPIID"][0])
1170 replace: schemaupdatenow
1173 self.ldb.modify_ldif(ldif)
1175 # If we add a new attribute with the same mAPIID, it should fail
1176 attr_name = "test-generated-mAPIID-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
1177 attr_ldap_display_name = attr_name.replace("-", "")
1178 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.25." + rand
1180 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1182 objectClass: attributeSchema
1183 adminDescription: """ + attr_name + """
1184 adminDisplayName: """ + attr_name + """
1185 cn: """ + attr_name + """
1186 attributeId: """ + attributeID + """
1187 mAPIID: """ + str(mAPIID_1) + """
1188 attributeSyntax: 2.5.5.1
1189 ldapDisplayName: """ + attr_ldap_display_name + """
1192 isSingleValued: TRUE
1197 self.ldb.add_ldif(ldif)
1198 self.fail("Should have failed to add duplicate mAPIID value")
1199 except LdbError as e22:
1200 (enum, estr) = e22.args
1201 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1204 def test_change_governsID(self):
1205 """Testing change the governsID"""
1206 rand = str(random.randint(1, 100000))
1207 class_name = "test-Class" + time.strftime("%s", time.gmtime()) + "-" + rand
1208 class_ldap_display_name = class_name.replace("-", "")
1209 governsID = "1.3.6.1.4.1.7165.4.6.2.6.5." + rand
1211 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1213 objectClass: classSchema
1214 adminDescription: """ + class_name + """
1215 adminDisplayName: """ + class_name + """
1216 cn: """ + class_name + """
1217 governsId: """ + governsID + """
1218 ldapDisplayName: """ + class_ldap_display_name + """
1220 objectClassCategory: 1
1221 subClassOf: organizationalPerson
1223 systemMustContain: cn
1226 self.ldb.add_ldif(ldif)
1229 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1232 governsId: """ + governsID + """.1
1236 self.ldb.modify_ldif(ldif)
1237 self.fail("Should have failed to modify schema to have different governsID")
1238 except LdbError as e23:
1239 (enum, estr) = e23.args
1240 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
1243 def test_change_governsID_same(self):
1244 """Testing change the governsID"""
1245 rand = str(random.randint(1, 100000))
1246 class_name = "test-Class" + time.strftime("%s", time.gmtime()) + "-" + rand
1247 class_ldap_display_name = class_name.replace("-", "")
1248 governsID = "1.3.6.1.4.1.7165.4.6.2.6.6." + rand
1250 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1252 objectClass: classSchema
1253 adminDescription: """ + class_name + """
1254 adminDisplayName: """ + class_name + """
1255 cn: """ + class_name + """
1256 governsId: """ + governsID + """
1257 ldapDisplayName: """ + class_ldap_display_name + """
1259 objectClassCategory: 1
1260 subClassOf: organizationalPerson
1262 systemMustContain: cn
1265 self.ldb.add_ldif(ldif)
1268 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1271 governsId: """ + governsID + """.1
1275 self.ldb.modify_ldif(ldif)
1276 self.fail("Should have failed to modify schema to have the same governsID")
1277 except LdbError as e24:
1278 (enum, estr) = e24.args
1279 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
1282 def test_subClassOf(self):
1283 """ Testing usage of custom child classSchema
1286 class_name = "my-Class" + time.strftime("%s", time.gmtime())
1287 class_ldap_display_name = class_name.replace("-", "")
1290 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1292 objectClass: classSchema
1293 adminDescription: """ + class_name + """
1294 adminDisplayName: """ + class_name + """
1295 cn: """ + class_name + """
1296 governsId: 1.3.6.1.4.1.7165.4.6.2.6.7.""" + str(random.randint(1, 100000)) + """
1298 objectClassCategory: 1
1299 subClassOf: organizationalUnit
1303 self.ldb.add_ldif(ldif)
1305 # Search for created objectclass
1307 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
1308 attrs=["lDAPDisplayName", "defaultObjectCategory",
1309 "schemaIDGUID", "distinguishedName"])
1310 self.assertEquals(len(res), 1)
1311 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
1312 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
1313 self.assertTrue("schemaIDGUID" in res[0])
1318 add: schemaUpdateNow
1321 self.ldb.modify_ldif(ldif)
1323 object_name = "org" + time.strftime("%s", time.gmtime())
1326 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
1327 objectClass: """ + class_ldap_display_name + """
1328 ou: """ + object_name + """
1331 self.ldb.add_ldif(ldif)
1333 # Search for created object
1335 res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
1336 self.assertEquals(len(res), 1)
1338 delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
1341 class SchemaTests_msDS_IntId(samba.tests.TestCase):
1344 super(SchemaTests_msDS_IntId, self).setUp()
1345 self.ldb = SamDB(host, credentials=creds,
1346 session_info=system_session(lp), lp=lp, options=ldb_options)
1347 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
1348 attrs=["schemaNamingContext", "defaultNamingContext",
1349 "forestFunctionality"])
1350 self.assertEquals(len(res), 1)
1351 self.schema_dn = res[0]["schemaNamingContext"][0]
1352 self.base_dn = res[0]["defaultNamingContext"][0]
1353 self.forest_level = int(res[0]["forestFunctionality"][0])
1355 def _ldap_schemaUpdateNow(self):
1359 add: schemaUpdateNow
1362 self.ldb.modify_ldif(ldif)
1364 def _make_obj_names(self, prefix):
1365 class_name = prefix + time.strftime("%s", time.gmtime())
1366 class_ldap_name = class_name.replace("-", "")
1367 class_dn = "CN=%s,%s" % (class_name, self.schema_dn)
1368 return (class_name, class_ldap_name, class_dn)
1370 def _is_schema_base_object(self, ldb_msg):
1371 """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)"""
1373 if "systemFlags" in ldb_msg:
1374 systemFlags = int(ldb_msg["systemFlags"][0])
1375 return (systemFlags & 16) != 0
1377 def _make_attr_ldif(self, attr_name, attr_dn):
1379 dn: """ + attr_dn + """
1381 objectClass: attributeSchema
1382 adminDescription: """ + attr_name + """
1383 adminDisplayName: """ + attr_name + """
1384 cn: """ + attr_name + """
1385 attributeId: 1.3.6.1.4.1.7165.4.6.1.6.14.""" + str(random.randint(1, 100000)) + """
1386 attributeSyntax: 2.5.5.12
1389 isSingleValued: TRUE
1394 def test_msDS_IntId_on_attr(self):
1395 """Testing msDs-IntId creation for Attributes.
1396 See MS-ADTS - 3.1.1.Attributes
1398 This test should verify that:
1399 - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM
1400 - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION
1401 - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag
1402 set fails with ERR_UNWILLING_TO_PERFORM
1403 - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have
1404 'msDS-IntId' attribute added internally
1407 # 1. Create attribute without systemFlags
1408 # msDS-IntId should be created if forest functional
1409 # level is >= DS_DOMAIN_FUNCTION_2003
1410 # and missing otherwise
1411 (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-")
1412 ldif = self._make_attr_ldif(attr_name, attr_dn)
1414 # try to add msDS-IntId during Attribute creation
1415 ldif_fail = ldif + "msDS-IntId: -1993108831\n"
1417 self.ldb.add_ldif(ldif_fail)
1418 self.fail("Adding attribute with preset msDS-IntId should fail")
1419 except LdbError as e25:
1421 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1423 # add the new attribute and update schema
1424 self.ldb.add_ldif(ldif)
1425 self._ldap_schemaUpdateNow()
1427 # Search for created attribute
1429 res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
1430 attrs=["lDAPDisplayName", "msDS-IntId", "systemFlags"])
1431 self.assertEquals(len(res), 1)
1432 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
1433 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1434 if self._is_schema_base_object(res[0]):
1435 self.assertTrue("msDS-IntId" not in res[0])
1437 self.assertTrue("msDS-IntId" in res[0])
1439 self.assertTrue("msDS-IntId" not in res[0])
1442 msg.dn = Dn(self.ldb, attr_dn)
1443 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1445 self.ldb.modify(msg)
1446 self.fail("Modifying msDS-IntId should return error")
1447 except LdbError as e26:
1449 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1451 # 2. Create attribute with systemFlags = FLAG_SCHEMA_BASE_OBJECT
1452 # msDS-IntId should be created if forest functional
1453 # level is >= DS_DOMAIN_FUNCTION_2003
1454 # and missing otherwise
1455 (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-2-")
1456 ldif = self._make_attr_ldif(attr_name, attr_dn)
1457 ldif += "systemFlags: 16\n"
1459 # try to add msDS-IntId during Attribute creation
1460 ldif_fail = ldif + "msDS-IntId: -1993108831\n"
1462 self.ldb.add_ldif(ldif_fail)
1463 self.fail("Adding attribute with preset msDS-IntId should fail")
1464 except LdbError as e27:
1466 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1468 # add the new attribute and update schema
1469 self.ldb.add_ldif(ldif)
1470 self._ldap_schemaUpdateNow()
1472 # Search for created attribute
1474 res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
1475 attrs=["lDAPDisplayName", "msDS-IntId"])
1476 self.assertEquals(len(res), 1)
1477 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
1478 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1479 if self._is_schema_base_object(res[0]):
1480 self.assertTrue("msDS-IntId" not in res[0])
1482 self.assertTrue("msDS-IntId" in res[0])
1484 self.assertTrue("msDS-IntId" not in res[0])
1487 msg.dn = Dn(self.ldb, attr_dn)
1488 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1490 self.ldb.modify(msg)
1491 self.fail("Modifying msDS-IntId should return error")
1492 except LdbError as e28:
1494 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1497 def _make_class_ldif(self, class_dn, class_name, sub_oid):
1499 dn: """ + class_dn + """
1501 objectClass: classSchema
1502 adminDescription: """ + class_name + """
1503 adminDisplayName: """ + class_name + """
1504 cn: """ + class_name + """
1505 governsId: 1.3.6.1.4.1.7165.4.6.2.6.%d.""" % sub_oid + str(random.randint(1, 100000)) + """
1507 objectClassCategory: 1
1508 subClassOf: organizationalPerson
1510 systemMustContain: cn
1515 def test_msDS_IntId_on_class(self):
1516 """Testing msDs-IntId creation for Class
1517 Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema"""
1519 # 1. Create Class without systemFlags
1520 # msDS-IntId should be created if forest functional
1521 # level is >= DS_DOMAIN_FUNCTION_2003
1522 # and missing otherwise
1523 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-")
1524 ldif = self._make_class_ldif(class_dn, class_name, 8)
1526 # try to add msDS-IntId during Class creation
1527 ldif_add = ldif + "msDS-IntId: -1993108831\n"
1528 self.ldb.add_ldif(ldif_add)
1529 self._ldap_schemaUpdateNow()
1531 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1532 self.assertEquals(len(res), 1)
1533 self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
1535 # add a new Class and update schema
1536 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-")
1537 ldif = self._make_class_ldif(class_dn, class_name, 9)
1539 self.ldb.add_ldif(ldif)
1540 self._ldap_schemaUpdateNow()
1542 # Search for created Class
1543 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1544 self.assertEquals(len(res), 1)
1545 self.assertFalse("msDS-IntId" in res[0])
1548 msg.dn = Dn(self.ldb, class_dn)
1549 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1551 self.ldb.modify(msg)
1552 self.fail("Modifying msDS-IntId should return error")
1553 except LdbError as e29:
1555 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1557 # 2. Create Class with systemFlags = FLAG_SCHEMA_BASE_OBJECT
1558 # msDS-IntId should be created if forest functional
1559 # level is >= DS_DOMAIN_FUNCTION_2003
1560 # and missing otherwise
1561 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-3-")
1562 ldif = self._make_class_ldif(class_dn, class_name, 10)
1563 ldif += "systemFlags: 16\n"
1565 # try to add msDS-IntId during Class creation
1566 ldif_add = ldif + "msDS-IntId: -1993108831\n"
1567 self.ldb.add_ldif(ldif_add)
1569 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1570 self.assertEquals(len(res), 1)
1571 self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
1573 # add the new Class and update schema
1574 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-4-")
1575 ldif = self._make_class_ldif(class_dn, class_name, 11)
1576 ldif += "systemFlags: 16\n"
1578 self.ldb.add_ldif(ldif)
1579 self._ldap_schemaUpdateNow()
1581 # Search for created Class
1582 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1583 self.assertEquals(len(res), 1)
1584 self.assertFalse("msDS-IntId" in res[0])
1587 msg.dn = Dn(self.ldb, class_dn)
1588 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1590 self.ldb.modify(msg)
1591 self.fail("Modifying msDS-IntId should return error")
1592 except LdbError as e30:
1594 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1595 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1596 self.assertEquals(len(res), 1)
1597 self.assertFalse("msDS-IntId" in res[0])
1600 def test_verify_msDS_IntId(self):
1601 """Verify msDS-IntId exists only on attributes without FLAG_SCHEMA_BASE_OBJECT flag set"""
1603 res = self.ldb.search(self.schema_dn, scope=SCOPE_ONELEVEL,
1604 expression="objectClass=attributeSchema",
1605 attrs=["systemFlags", "msDS-IntId", "attributeID", "cn"])
1606 self.assertTrue(len(res) > 1)
1608 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1609 if self._is_schema_base_object(ldb_msg):
1610 self.assertTrue("msDS-IntId" not in ldb_msg)
1612 # don't assert here as there are plenty of
1613 # attributes under w2k8 that are not part of
1614 # Base Schema (SYSTEM_FLAG_SCHEMA_BASE_OBJECT flag not set)
1615 # has not msDS-IntId attribute set
1616 #self.assertTrue("msDS-IntId" in ldb_msg, "msDS-IntId expected on: %s" % ldb_msg.dn)
1617 if "msDS-IntId" not in ldb_msg:
1619 print("%3d warning: msDS-IntId expected on: %-30s %s" % (count, ldb_msg["attributeID"], ldb_msg["cn"]))
1621 self.assertTrue("msDS-IntId" not in ldb_msg)
1624 class SchemaTests_msDS_isRODC(samba.tests.TestCase):
1627 super(SchemaTests_msDS_isRODC, self).setUp()
1628 self.ldb = SamDB(host, credentials=creds,
1629 session_info=system_session(lp), lp=lp, options=ldb_options)
1630 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["defaultNamingContext"])
1631 self.assertEquals(len(res), 1)
1632 self.base_dn = res[0]["defaultNamingContext"][0]
1634 def test_objectClass_ntdsdsa(self):
1635 res = self.ldb.search(self.base_dn, expression="objectClass=nTDSDSA",
1636 attrs=["msDS-isRODC"], controls=["search_options:1:2"])
1638 self.assertTrue("msDS-isRODC" in ldb_msg)
1640 def test_objectClass_server(self):
1641 res = self.ldb.search(self.base_dn, expression="objectClass=server",
1642 attrs=["msDS-isRODC"], controls=["search_options:1:2"])
1644 ntds_search_dn = "CN=NTDS Settings,%s" % ldb_msg['dn']
1646 res_check = self.ldb.search(ntds_search_dn, attrs=["objectCategory"])
1647 except LdbError as e:
1649 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1650 print("Server entry %s doesn't have a NTDS settings object" % res[0]['dn'])
1652 self.assertTrue("objectCategory" in res_check[0])
1653 self.assertTrue("msDS-isRODC" in ldb_msg)
1655 def test_objectClass_computer(self):
1656 res = self.ldb.search(self.base_dn, expression="objectClass=computer",
1657 attrs=["serverReferenceBL", "msDS-isRODC"], controls=["search_options:1:2"])
1659 if "serverReferenceBL" not in ldb_msg:
1660 print("Computer entry %s doesn't have a serverReferenceBL attribute" % ldb_msg['dn'])
1662 self.assertTrue("msDS-isRODC" in ldb_msg)
1664 if not "://" in host:
1665 if os.path.isfile(host):
1666 host = "tdb://%s" % host
1668 host = "ldap://%s" % host
1671 if host.startswith("ldap://"):
1672 # user 'paged_search' module when connecting remotely
1673 ldb_options = ["modules:paged_searches"]
1675 TestProgram(module=__name__, opts=subunitopts)