repl_meta_data: Correctly use msDS-IntId for custom schema, not the prefixMap value
[abartlet/samba.git/.git] / source4 / dsdb / tests / python / ldap_schema.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
4
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2011
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
21
22 import optparse
23 import sys
24 import time
25 import random
26 import os
27
28 sys.path.insert(0, "bin/python")
29 import samba
30 from samba.tests.subunitrun import TestProgram, SubunitOptions
31
32 import samba.getopt as options
33
34 from samba.auth import system_session
35 from ldb import SCOPE_ONELEVEL, SCOPE_BASE, LdbError
36 from ldb import ERR_NO_SUCH_OBJECT
37 from ldb import ERR_UNWILLING_TO_PERFORM
38 from ldb import ERR_CONSTRAINT_VIOLATION
39 from ldb import Message, MessageElement, Dn
40 from ldb import FLAG_MOD_REPLACE
41 from samba.samdb import SamDB
42 from samba.dsdb import DS_DOMAIN_FUNCTION_2003
43 from samba.tests import delete_force
44 from samba.ndr import ndr_unpack
45 from samba.dcerpc import drsblobs
46
47 parser = optparse.OptionParser("ldap_schema.py [options] <host>")
48 sambaopts = options.SambaOptions(parser)
49 parser.add_option_group(sambaopts)
50 parser.add_option_group(options.VersionOptions(parser))
51 # use command line creds if available
52 credopts = options.CredentialsOptions(parser)
53 parser.add_option_group(credopts)
54 subunitopts = SubunitOptions(parser)
55 parser.add_option_group(subunitopts)
56 opts, args = parser.parse_args()
57
58 if len(args) < 1:
59     parser.print_usage()
60     sys.exit(1)
61
62 host = args[0]
63
64 lp = sambaopts.get_loadparm()
65 creds = credopts.get_credentials(lp)
66
67
68 class SchemaTests(samba.tests.TestCase):
69
70     def setUp(self):
71         super(SchemaTests, self).setUp()
72         self.ldb = SamDB(host, credentials=creds,
73             session_info=system_session(lp), lp=lp, options=ldb_options)
74         self.base_dn = self.ldb.domain_dn()
75         self.schema_dn = self.ldb.get_schema_basedn().get_linearized()
76
77     def test_generated_schema(self):
78         """Testing we can read the generated schema via LDAP"""
79         res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
80                 attrs=["objectClasses", "attributeTypes", "dITContentRules"])
81         self.assertEquals(len(res), 1)
82         self.assertTrue("dITContentRules" in res[0])
83         self.assertTrue("objectClasses" in res[0])
84         self.assertTrue("attributeTypes" in res[0])
85
86     def test_generated_schema_is_operational(self):
87         """Testing we don't get the generated schema via LDAP by default"""
88         # Must keep the "*" form
89         res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
90                               attrs=["*"])
91         self.assertEquals(len(res), 1)
92         self.assertFalse("dITContentRules" in res[0])
93         self.assertFalse("objectClasses" in res[0])
94         self.assertFalse("attributeTypes" in res[0])
95
96     def test_schemaUpdateNow(self):
97         """Testing schemaUpdateNow"""
98         attr_name = "test-Attr" + time.strftime("%s", time.gmtime())
99         attr_ldap_display_name = attr_name.replace("-", "")
100
101         ldif = """
102 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
103 objectClass: top
104 objectClass: attributeSchema
105 adminDescription: """ + attr_name + """
106 adminDisplayName: """ + attr_name + """
107 cn: """ + attr_name + """
108 attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
109 attributeSyntax: 2.5.5.12
110 omSyntax: 64
111 instanceType: 4
112 isSingleValued: TRUE
113 systemOnly: FALSE
114 """
115         self.ldb.add_ldif(ldif)
116         # We must do a schemaUpdateNow otherwise it's not 100% sure that the schema
117         # will contain the new attribute
118         ldif = """
119 dn:
120 changetype: modify
121 add: schemaUpdateNow
122 schemaUpdateNow: 1
123 """
124         self.ldb.modify_ldif(ldif)
125
126         # Search for created attribute
127         res = []
128         res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE,
129                               attrs=["lDAPDisplayName","schemaIDGUID", "msDS-IntID"])
130         self.assertEquals(len(res), 1)
131         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
132         self.assertTrue("schemaIDGUID" in res[0])
133         if "msDS-IntId" in res[0]:
134             msDS_IntId = int(res[0]["msDS-IntId"][0])
135             if msDS_IntId < 0:
136                 msDS_IntId += (1 << 32)
137         else:
138             msDS_IntId = None
139
140         class_name = "test-Class" + time.strftime("%s", time.gmtime())
141         class_ldap_display_name = class_name.replace("-", "")
142
143         # First try to create a class with a wrong "defaultObjectCategory"
144         ldif = """
145 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
146 objectClass: top
147 objectClass: classSchema
148 defaultObjectCategory: CN=_
149 adminDescription: """ + class_name + """
150 adminDisplayName: """ + class_name + """
151 cn: """ + class_name + """
152 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
153 instanceType: 4
154 objectClassCategory: 1
155 subClassOf: organizationalPerson
156 systemFlags: 16
157 rDNAttID: cn
158 systemMustContain: cn
159 systemMustContain: """ + attr_ldap_display_name + """
160 systemOnly: FALSE
161 """
162         try:
163                  self.ldb.add_ldif(ldif)
164                  self.fail()
165         except LdbError, (num, _):
166                  self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
167
168         ldif = """
169 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
170 objectClass: top
171 objectClass: classSchema
172 adminDescription: """ + class_name + """
173 adminDisplayName: """ + class_name + """
174 cn: """ + class_name + """
175 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
176 instanceType: 4
177 objectClassCategory: 1
178 subClassOf: organizationalPerson
179 systemFlags: 16
180 rDNAttID: cn
181 systemMustContain: cn
182 systemMustContain: """ + attr_ldap_display_name + """
183 systemOnly: FALSE
184 """
185         self.ldb.add_ldif(ldif)
186
187         # Search for created objectclass
188         res = []
189         res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
190                               attrs=["lDAPDisplayName", "defaultObjectCategory", "schemaIDGUID", "distinguishedName"])
191         self.assertEquals(len(res), 1)
192         self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
193         self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
194         self.assertTrue("schemaIDGUID" in res[0])
195
196         ldif = """
197 dn:
198 changetype: modify
199 add: schemaUpdateNow
200 schemaUpdateNow: 1
201 """
202         self.ldb.modify_ldif(ldif)
203
204         object_name = "obj" + time.strftime("%s", time.gmtime())
205
206         ldif = """
207 dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
208 objectClass: organizationalPerson
209 objectClass: person
210 objectClass: """ + class_ldap_display_name + """
211 objectClass: top
212 cn: """ + object_name + """
213 instanceType: 4
214 objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """
215 distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
216 name: """ + object_name + """
217 """ + attr_ldap_display_name + """: test
218 """
219         self.ldb.add_ldif(ldif)
220
221         # Search for created object
222         obj_res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["replPropertyMetaData"])
223
224         self.assertEquals(len(obj_res), 1)
225         self.assertTrue("replPropertyMetaData" in obj_res[0])
226         val = obj_res[0]["replPropertyMetaData"][0]
227         repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
228         obj = repl.ctr
229
230         # Windows 2000 functional level won't have this.  It is too
231         # hard to work it out from the prefixmap however, so we skip
232         # this test in that case.
233         if msDS_IntId is not None:
234             found = False
235             for o in repl.ctr.array:
236                 if o.attid == msDS_IntId:
237                     found = True
238                     break
239             self.assertTrue(found, "Did not find 0x%08x in replPropertyMetaData" % msDS_IntId)
240         # Delete the object
241         delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
242
243     def test_subClassOf(self):
244         """ Testing usage of custom child schamaClass
245         """
246
247         class_name = "my-Class" + time.strftime("%s", time.gmtime())
248         class_ldap_display_name = class_name.replace("-", "")
249
250         ldif = """
251 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
252 objectClass: top
253 objectClass: classSchema
254 adminDescription: """ + class_name + """
255 adminDisplayName: """ + class_name + """
256 cn: """ + class_name + """
257 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
258 instanceType: 4
259 objectClassCategory: 1
260 subClassOf: organizationalUnit
261 systemFlags: 16
262 systemOnly: FALSE
263 """
264         self.ldb.add_ldif(ldif)
265
266         # Search for created objectclass
267         res = []
268         res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
269                               attrs=["lDAPDisplayName", "defaultObjectCategory",
270                                      "schemaIDGUID", "distinguishedName"])
271         self.assertEquals(len(res), 1)
272         self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
273         self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
274         self.assertTrue("schemaIDGUID" in res[0])
275
276         ldif = """
277 dn:
278 changetype: modify
279 add: schemaUpdateNow
280 schemaUpdateNow: 1
281 """
282         self.ldb.modify_ldif(ldif)
283
284         object_name = "org" + time.strftime("%s", time.gmtime())
285
286         ldif = """
287 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
288 objectClass: """ + class_ldap_display_name + """
289 ou: """ + object_name + """
290 instanceType: 4
291 """
292         self.ldb.add_ldif(ldif)
293
294         # Search for created object
295         res = []
296         res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
297         self.assertEquals(len(res), 1)
298         # Delete the object
299         delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
300
301
302 class SchemaTests_msDS_IntId(samba.tests.TestCase):
303
304     def setUp(self):
305         super(SchemaTests_msDS_IntId, self).setUp()
306         self.ldb = SamDB(host, credentials=creds,
307             session_info=system_session(lp), lp=lp, options=ldb_options)
308         res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
309                          attrs=["schemaNamingContext", "defaultNamingContext",
310                                 "forestFunctionality"])
311         self.assertEquals(len(res), 1)
312         self.schema_dn = res[0]["schemaNamingContext"][0]
313         self.base_dn = res[0]["defaultNamingContext"][0]
314         self.forest_level = int(res[0]["forestFunctionality"][0])
315
316     def _ldap_schemaUpdateNow(self):
317         ldif = """
318 dn:
319 changetype: modify
320 add: schemaUpdateNow
321 schemaUpdateNow: 1
322 """
323         self.ldb.modify_ldif(ldif)
324
325     def _make_obj_names(self, prefix):
326         class_name = prefix + time.strftime("%s", time.gmtime())
327         class_ldap_name = class_name.replace("-", "")
328         class_dn = "CN=%s,%s" % (class_name, self.schema_dn)
329         return (class_name, class_ldap_name, class_dn)
330
331     def _is_schema_base_object(self, ldb_msg):
332         """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)"""
333         systemFlags = 0
334         if "systemFlags" in ldb_msg:
335             systemFlags = int(ldb_msg["systemFlags"][0])
336         return (systemFlags & 16) != 0
337
338     def _make_attr_ldif(self, attr_name, attr_dn):
339         ldif = """
340 dn: """ + attr_dn + """
341 objectClass: top
342 objectClass: attributeSchema
343 adminDescription: """ + attr_name + """
344 adminDisplayName: """ + attr_name + """
345 cn: """ + attr_name + """
346 attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
347 attributeSyntax: 2.5.5.12
348 omSyntax: 64
349 instanceType: 4
350 isSingleValued: TRUE
351 systemOnly: FALSE
352 """
353         return ldif
354
355     def test_msDS_IntId_on_attr(self):
356         """Testing msDs-IntId creation for Attributes.
357         See MS-ADTS - 3.1.1.Attributes
358
359         This test should verify that:
360         - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM
361         - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION
362         - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag
363           set fails with ERR_UNWILLING_TO_PERFORM
364         - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have
365           'msDS-IntId' attribute added internally
366         """
367
368         # 1. Create attribute without systemFlags
369         # msDS-IntId should be created if forest functional
370         # level is >= DS_DOMAIN_FUNCTION_2003
371         # and missing otherwise
372         (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-")
373         ldif = self._make_attr_ldif(attr_name, attr_dn)
374
375         # try to add msDS-IntId during Attribute creation
376         ldif_fail = ldif + "msDS-IntId: -1993108831\n"
377         try:
378             self.ldb.add_ldif(ldif_fail)
379             self.fail("Adding attribute with preset msDS-IntId should fail")
380         except LdbError, (num, _):
381             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
382
383         # add the new attribute and update schema
384         self.ldb.add_ldif(ldif)
385         self._ldap_schemaUpdateNow()
386
387         # Search for created attribute
388         res = []
389         res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
390                               attrs=["lDAPDisplayName", "msDS-IntId", "systemFlags"])
391         self.assertEquals(len(res), 1)
392         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
393         if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
394             if self._is_schema_base_object(res[0]):
395                 self.assertTrue("msDS-IntId" not in res[0])
396             else:
397                 self.assertTrue("msDS-IntId" in res[0])
398         else:
399             self.assertTrue("msDS-IntId" not in res[0])
400
401         msg = Message()
402         msg.dn = Dn(self.ldb, attr_dn)
403         msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
404         try:
405             self.ldb.modify(msg)
406             self.fail("Modifying msDS-IntId should return error")
407         except LdbError, (num, _):
408             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
409
410         # 2. Create attribute with systemFlags = FLAG_SCHEMA_BASE_OBJECT
411         # msDS-IntId should be created if forest functional
412         # level is >= DS_DOMAIN_FUNCTION_2003
413         # and missing otherwise
414         (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-2-")
415         ldif = self._make_attr_ldif(attr_name, attr_dn)
416         ldif += "systemFlags: 16\n"
417
418         # try to add msDS-IntId during Attribute creation
419         ldif_fail = ldif + "msDS-IntId: -1993108831\n"
420         try:
421             self.ldb.add_ldif(ldif_fail)
422             self.fail("Adding attribute with preset msDS-IntId should fail")
423         except LdbError, (num, _):
424             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
425
426         # add the new attribute and update schema
427         self.ldb.add_ldif(ldif)
428         self._ldap_schemaUpdateNow()
429
430         # Search for created attribute
431         res = []
432         res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
433                               attrs=["lDAPDisplayName", "msDS-IntId"])
434         self.assertEquals(len(res), 1)
435         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
436         if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
437             if self._is_schema_base_object(res[0]):
438                 self.assertTrue("msDS-IntId" not in res[0])
439             else:
440                 self.assertTrue("msDS-IntId" in res[0])
441         else:
442             self.assertTrue("msDS-IntId" not in res[0])
443
444         msg = Message()
445         msg.dn = Dn(self.ldb, attr_dn)
446         msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
447         try:
448             self.ldb.modify(msg)
449             self.fail("Modifying msDS-IntId should return error")
450         except LdbError, (num, _):
451             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
452
453
454     def _make_class_ldif(self, class_dn, class_name):
455         ldif = """
456 dn: """ + class_dn + """
457 objectClass: top
458 objectClass: classSchema
459 adminDescription: """ + class_name + """
460 adminDisplayName: """ + class_name + """
461 cn: """ + class_name + """
462 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
463 instanceType: 4
464 objectClassCategory: 1
465 subClassOf: organizationalPerson
466 rDNAttID: cn
467 systemMustContain: cn
468 systemOnly: FALSE
469 """
470         return ldif
471
472     def test_msDS_IntId_on_class(self):
473         """Testing msDs-IntId creation for Class
474            Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema"""
475
476         # 1. Create Class without systemFlags
477         # msDS-IntId should be created if forest functional
478         # level is >= DS_DOMAIN_FUNCTION_2003
479         # and missing otherwise
480         (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-")
481         ldif = self._make_class_ldif(class_dn, class_name)
482
483         # try to add msDS-IntId during Class creation
484         ldif_add = ldif + "msDS-IntId: -1993108831\n"
485         self.ldb.add_ldif(ldif_add)
486         self._ldap_schemaUpdateNow()
487
488         res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
489         self.assertEquals(len(res), 1)
490         self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
491
492         # add a new Class and update schema
493         (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-")
494         ldif = self._make_class_ldif(class_dn, class_name)
495
496         self.ldb.add_ldif(ldif)
497         self._ldap_schemaUpdateNow()
498
499         # Search for created Class
500         res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
501         self.assertEquals(len(res), 1)
502         self.assertFalse("msDS-IntId" in res[0])
503
504         msg = Message()
505         msg.dn = Dn(self.ldb, class_dn)
506         msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
507         try:
508             self.ldb.modify(msg)
509             self.fail("Modifying msDS-IntId should return error")
510         except LdbError, (num, _):
511             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
512
513         # 2. Create Class with systemFlags = FLAG_SCHEMA_BASE_OBJECT
514         # msDS-IntId should be created if forest functional
515         # level is >= DS_DOMAIN_FUNCTION_2003
516         # and missing otherwise
517         (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-3-")
518         ldif = self._make_class_ldif(class_dn, class_name)
519         ldif += "systemFlags: 16\n"
520
521         # try to add msDS-IntId during Class creation
522         ldif_add = ldif + "msDS-IntId: -1993108831\n"
523         self.ldb.add_ldif(ldif_add)
524
525         res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
526         self.assertEquals(len(res), 1)
527         self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
528
529         # add the new Class and update schema
530         (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-4-")
531         ldif = self._make_class_ldif(class_dn, class_name)
532         ldif += "systemFlags: 16\n"
533
534         self.ldb.add_ldif(ldif)
535         self._ldap_schemaUpdateNow()
536
537         # Search for created Class
538         res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
539         self.assertEquals(len(res), 1)
540         self.assertFalse("msDS-IntId" in res[0])
541
542         msg = Message()
543         msg.dn = Dn(self.ldb, class_dn)
544         msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
545         try:
546             self.ldb.modify(msg)
547             self.fail("Modifying msDS-IntId should return error")
548         except LdbError, (num, _):
549             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
550         res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
551         self.assertEquals(len(res), 1)
552         self.assertFalse("msDS-IntId" in res[0])
553
554
555     def test_verify_msDS_IntId(self):
556         """Verify msDS-IntId exists only on attributes without FLAG_SCHEMA_BASE_OBJECT flag set"""
557         count = 0
558         res = self.ldb.search(self.schema_dn, scope=SCOPE_ONELEVEL,
559                               expression="objectClass=attributeSchema",
560                               attrs=["systemFlags", "msDS-IntId", "attributeID", "cn"])
561         self.assertTrue(len(res) > 1)
562         for ldb_msg in res:
563             if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
564                 if self._is_schema_base_object(ldb_msg):
565                     self.assertTrue("msDS-IntId" not in ldb_msg)
566                 else:
567                     # don't assert here as there are plenty of
568                     # attributes under w2k8 that are not part of
569                     # Base Schema (SYSTEM_FLAG_SCHEMA_BASE_OBJECT flag not set)
570                     # has not msDS-IntId attribute set
571                     #self.assertTrue("msDS-IntId" in ldb_msg, "msDS-IntId expected on: %s" % ldb_msg.dn)
572                     if "msDS-IntId" not in ldb_msg:
573                         count = count + 1
574                         print "%3d warning: msDS-IntId expected on: %-30s %s" % (count, ldb_msg["attributeID"], ldb_msg["cn"])
575             else:
576                 self.assertTrue("msDS-IntId" not in ldb_msg)
577
578
579 class SchemaTests_msDS_isRODC(samba.tests.TestCase):
580
581     def setUp(self):
582         super(SchemaTests_msDS_isRODC, self).setUp()
583         self.ldb =  SamDB(host, credentials=creds,
584             session_info=system_session(lp), lp=lp, options=ldb_options)
585         res = self.ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["defaultNamingContext"])
586         self.assertEquals(len(res), 1)
587         self.base_dn = res[0]["defaultNamingContext"][0]
588
589     def test_objectClass_ntdsdsa(self):
590         res = self.ldb.search(self.base_dn, expression="objectClass=nTDSDSA",
591                               attrs=["msDS-isRODC"], controls=["search_options:1:2"])
592         for ldb_msg in res:
593             self.assertTrue("msDS-isRODC" in ldb_msg)
594
595     def test_objectClass_server(self):
596         res = self.ldb.search(self.base_dn, expression="objectClass=server",
597                               attrs=["msDS-isRODC"], controls=["search_options:1:2"])
598         for ldb_msg in res:
599             ntds_search_dn = "CN=NTDS Settings,%s" % ldb_msg['dn']
600             try:
601                 res_check = self.ldb.search(ntds_search_dn, attrs=["objectCategory"])
602             except LdbError, (num, _):
603                 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
604                 print("Server entry %s doesn't have a NTDS settings object" % res[0]['dn'])
605             else:
606                 self.assertTrue("objectCategory" in res_check[0])
607                 self.assertTrue("msDS-isRODC" in ldb_msg)
608
609     def test_objectClass_computer(self):
610         res = self.ldb.search(self.base_dn, expression="objectClass=computer",
611                               attrs=["serverReferenceBL","msDS-isRODC"], controls=["search_options:1:2"])
612         for ldb_msg in res:
613             if "serverReferenceBL" not in ldb_msg:
614                 print("Computer entry %s doesn't have a serverReferenceBL attribute" % ldb_msg['dn'])
615             else:
616                 self.assertTrue("msDS-isRODC" in ldb_msg)
617
618 if not "://" in host:
619     if os.path.isfile(host):
620         host = "tdb://%s" % host
621     else:
622         host = "ldap://%s" % host
623
624 ldb_options = []
625 if host.startswith("ldap://"):
626     # user 'paged_search' module when connecting remotely
627     ldb_options = ["modules:paged_searches"]
628
629 TestProgram(module=__name__, opts=subunitopts)