#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Andrew Tridgell 2009
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""Tests the possibleInferiors generation in the schema_fsmo ldb module"""
import optparse
import sys
# Find right directory when running from source tree
sys.path.insert(0, "bin/python")
import samba
from samba import getopt as options, Ldb
import ldb
parser = optparse.OptionParser("possibleinferiors.py []")
sambaopts = options.SambaOptions(parser)
parser.add_option_group(sambaopts)
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)
parser.add_option_group(options.VersionOptions(parser))
opts, args = parser.parse_args()
if len(args) < 1:
parser.print_usage()
sys.exit(1)
url = args[0]
if (len(args) > 1):
objectclass = args[1]
else:
objectclass = None
def uniq_list(alist):
"""return a unique list"""
set = {}
return [set.setdefault(e,e) for e in alist if e not in set]
lp_ctx = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp_ctx)
db = Ldb(url, credentials=creds, lp=lp_ctx, options=["modules:paged_searches"])
# get the rootDSE
res = db.search(base="", expression="",
scope=ldb.SCOPE_BASE,
attrs=["schemaNamingContext"])
rootDse = res[0]
schema_base = rootDse["schemaNamingContext"][0]
def possible_inferiors_search(db, oc):
"""return the possible inferiors via a search for the possibleInferiors attribute"""
res = db.search(base=schema_base,
expression=("ldapdisplayname=%s" % oc),
attrs=["possibleInferiors"])
poss=[]
if len(res) == 0 or res[0].get("possibleInferiors") is None:
return poss
for item in res[0]["possibleInferiors"]:
poss.append(str(item))
poss = uniq_list(poss)
poss.sort()
return poss;
# see [MS-ADTS] section 3.1.1.4.5.21
# for this algorithm
# !systemOnly=TRUE
# !objectClassCategory=2
# !objectClassCategory=3
def POSSINFERIORS(db, oc):
"""returns a list of possible inferiors to a class. Returned list has the ldapdisplayname, systemOnly and objectClassCategory for each element"""
expanded = [oc]
res = db.search(base=schema_base,
expression=("subclassof=%s" % str(oc["ldapdisplayname"][0])),
attrs=["ldapdisplayname", "systemOnly", "objectClassCategory"])
for r in res:
expanded.extend(POSSINFERIORS(db,r))
return expanded
def possible_inferiors_constructed(db, oc):
"""return the possbible inferiors via a recursive search and match"""
res = db.search(base=schema_base,
expression=("(&(objectclass=classSchema)(|(posssuperiors=%s)(systemposssuperiors=%s)))" % (oc,oc)),
attrs=["ldapdisplayname", "systemOnly", "objectClassCategory"])
poss = []
for r in res:
poss.extend(POSSINFERIORS(db,r))
poss2 = []
for p in poss:
if (not (p["systemOnly"][0] == "TRUE" or
int(p["objectClassCategory"][0]) == 2 or
int(p["objectClassCategory"][0]) == 3)):
poss2.append(p["ldapdisplayname"][0])
poss2 = uniq_list(poss2)
poss2.sort()
return poss2
def test_class(db, oc):
"""test to see if one objectclass returns the correct possibleInferiors"""
poss1 = possible_inferiors_search(db, oc)
poss2 = possible_inferiors_constructed(db, oc)
if poss1 != poss2:
print "Returned incorrect list for objectclass %s" % oc
print poss1
print poss2
for i in range(0,min(len(poss1),len(poss2))):
print "%30s %30s" % (poss1[i], poss2[i])
exit(1)
def get_object_classes(db):
"""return a list of all object classes"""
res = db.search(base=schema_base,
expression="objectClass=classSchema",
attrs=["ldapdisplayname"])
list=[]
for item in res:
list.append(item["ldapdisplayname"][0])
return list
if objectclass is None:
for oc in get_object_classes(db):
print "testing objectClass %s" % oc
test_class(db,oc)
else:
test_class(db,objectclass)
print "Lists match OK"