From a48f19b6c2c954e743438e9f2814289247ba3fc6 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 18 Sep 2008 21:32:30 +0200 Subject: Remove python extension, simplify some code. --- source4/scripting/bin/minschema.py | 585 ------------------------------------- 1 file changed, 585 deletions(-) delete mode 100755 source4/scripting/bin/minschema.py (limited to 'source4/scripting/bin/minschema.py') diff --git a/source4/scripting/bin/minschema.py b/source4/scripting/bin/minschema.py deleted file mode 100755 index 111557126d..0000000000 --- a/source4/scripting/bin/minschema.py +++ /dev/null @@ -1,585 +0,0 @@ -#!/usr/bin/python -# -# work out the minimal schema for a set of objectclasses -# - -import optparse - -import os, sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba -from samba import getopt as options -import sys - -parser = optparse.OptionParser("minschema ") -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)) -parser.add_option("--verbose", help="Be verbose", action="store_true") -parser.add_option("--dump-classes", action="store_true") -parser.add_option("--dump-attributes", action="store_true") -parser.add_option("--dump-subschema", action="store_true") -parser.add_option("--dump-subschema-auto", action="store_true") - -opts, args = parser.parse_args() -opts.dump_all = True - -if opts.dump_classes: - opts.dump_all = False -if opts.dump_attributes: - opts.dump_all = False -if opts.dump_subschema: - opts.dump_all = False -if opts.dump_subschema_auto: - opts.dump_all = False - opts.dump_subschema = True -if opts.dump_all: - opts.dump_classes = True - opts.dump_attributes = True - opts.dump_subschema = True - opts.dump_subschema_auto = True - -if len(args) != 2: - parser.print_usage() - sys.exit(1) - -(url, classfile) = args - -creds = credopts.get_credentials() -ldb = Ldb(url, credentials=creds) - -objectclasses = [] -attributes = [] - -objectclasses_expanded = set() - -# the attributes we need for objectclasses -class_attrs = ["objectClass", - "subClassOf", - "governsID", - "possSuperiors", - "possibleInferiors", - "mayContain", - "mustContain", - "auxiliaryClass", - "rDNAttID", - "showInAdvancedViewOnly", - "adminDisplayName", - "adminDescription", - "objectClassCategory", - "lDAPDisplayName", - "schemaIDGUID", - "systemOnly", - "systemPossSuperiors", - "systemMayContain", - "systemMustContain", - "systemAuxiliaryClass", - "defaultSecurityDescriptor", - "systemFlags", - "defaultHidingValue", - "objectCategory", - "defaultObjectCategory", - - # this attributes are not used by w2k3 - "schemaFlagsEx", - "msDs-IntId", - "msDs-Schema-Extensions", - "classDisplayName", - "isDefunct"] - -attrib_attrs = ["objectClass", - "attributeID", - "attributeSyntax", - "isSingleValued", - "rangeLower", - "rangeUpper", - "mAPIID", - "linkID", - "showInAdvancedViewOnly", - "adminDisplayName", - "oMObjectClass", - "adminDescription", - "oMSyntax", - "searchFlags", - "extendedCharsAllowed", - "lDAPDisplayName", - "schemaIDGUID", - "attributeSecurityGUID", - "systemOnly", - "systemFlags", - "isMemberOfPartialAttributeSet", - "objectCategory", - - # this attributes are not used by w2k3 - "schemaFlagsEx", - "msDs-IntId", - "msDs-Schema-Extensions", - "classDisplayName", - "isEphemeral", - "isDefunct"] - -# -# notes: -# -# objectClassCategory -# 1: structural -# 2: abstract -# 3: auxiliary - -# -# print only if verbose is set -# -def dprintf(text): - if verbose is not None: - print text - -def get_object_cn(ldb, name): - attrs = ["cn"] - - res = ldb.search("(ldapDisplayName=%s)" % name, rootDse["schemaNamingContext"], ldb.SCOPE_SUBTREE, attrs) - assert len(res) == 1 - - return res[0]["cn"] - -class Objectclass: - def __init__(self, ldb, name): - """create an objectclass object""" - self.name = name - self.cn = get_object_cn(ldb, name) - - -class Attribute: - def __init__(self, ldb, name): - """create an attribute object""" - self.name = name - self.cn = get_object_cn(ldb, name) - - -syntaxmap = dict() - -syntaxmap['2.5.5.1'] = '1.3.6.1.4.1.1466.115.121.1.12' -syntaxmap['2.5.5.2'] = '1.3.6.1.4.1.1466.115.121.1.38' -syntaxmap['2.5.5.3'] = '1.2.840.113556.1.4.1362' -syntaxmap['2.5.5.4'] = '1.2.840.113556.1.4.905' -syntaxmap['2.5.5.5'] = '1.3.6.1.4.1.1466.115.121.1.26' -syntaxmap['2.5.5.6'] = '1.3.6.1.4.1.1466.115.121.1.36' -syntaxmap['2.5.5.7'] = '1.2.840.113556.1.4.903' -syntaxmap['2.5.5.8'] = '1.3.6.1.4.1.1466.115.121.1.7' -syntaxmap['2.5.5.9'] = '1.3.6.1.4.1.1466.115.121.1.27' -syntaxmap['2.5.5.10'] = '1.3.6.1.4.1.1466.115.121.1.40' -syntaxmap['2.5.5.11'] = '1.3.6.1.4.1.1466.115.121.1.24' -syntaxmap['2.5.5.12'] = '1.3.6.1.4.1.1466.115.121.1.15' -syntaxmap['2.5.5.13'] = '1.3.6.1.4.1.1466.115.121.1.43' -syntaxmap['2.5.5.14'] = '1.2.840.113556.1.4.904' -syntaxmap['2.5.5.15'] = '1.2.840.113556.1.4.907' -syntaxmap['2.5.5.16'] = '1.2.840.113556.1.4.906' -syntaxmap['2.5.5.17'] = '1.3.6.1.4.1.1466.115.121.1.40' - - -def map_attribute_syntax(s): - """map some attribute syntaxes from some apparently MS specific - syntaxes to the standard syntaxes""" - if syntaxmap.has_key(s): - return syntaxmap[s] - return s - - -def fix_dn(dn): - """fix a string DN to use ${SCHEMADN}""" - return dn.replace(rootDse["schemaNamingContext"], "${SCHEMADN}") - - -def write_ldif_one(o, attrs): - """dump an object as ldif""" - print "dn: CN=%s,${SCHEMADN}\n" % o["cn"] - for a in attrs: - if not o.has_key(a): - continue - # special case for oMObjectClass, which is a binary object - if a == "oMObjectClass": - print "%s:: %s\n" % (a, o[a]) - continue - v = o[a] - if isinstance(v, str): - v = [v] - for j in v: - print "%s: %s\n" % (a, fix_dn(j)) - print "\n" - -def write_ldif(o, attrs): - """dump an array of objects as ldif""" - for i in o: - write_ldif_one(i, attrs) - - -def create_testdn(exampleDN): - """create a testDN based an an example DN - the idea is to ensure we obey any structural rules""" - a = exampleDN.split(",") - a[0] = "CN=TestDN" - return ",".join(a) - - -def find_objectclass_properties(ldb, o): - """the properties of an objectclass""" - res = ldb.search( - expression="(ldapDisplayName=%s)" % o.name, - basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE, attrs=class_attrs) - assert(len(res) == 1) - msg = res[0] - for a in msg: - o[a] = msg[a] - -def find_attribute_properties(ldb, o): - """find the properties of an attribute""" - res = ldb.search( - expression="(ldapDisplayName=%s)" % o.name, - basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE, - attrs=attrib_attrs) - assert(len(res) == 1) - msg = res[0] - for a in msg: - # special case for oMObjectClass, which is a binary object - if a == "oMObjectClass": - o[a] = ldb.encode(msg[a]) - continue - o[a] = msg[a] - - -def find_objectclass_auto(ldb, o): - """find the auto-created properties of an objectclass. Only works for - classes that can be created using just a DN and the objectclass""" - if not o.has_key("exampleDN"): - return - testdn = create_testdn(o.exampleDN) - - print "testdn is '%s'\n" % testdn - - ldif = "dn: " + testdn - ldif += "\nobjectClass: " + o.name - try: - ldb.add(ldif) - except LdbError, e: - print "error adding %s: %s\n" % (o.name, e) - print "%s\n" % ldif - return - - res = ldb.search("", testdn, ldb.SCOPE_BASE) - ldb.delete(testdn) - - for a in res.msgs[0]: - attributes[a].autocreate = True - - -def expand_objectclass(ldb, o): - """look at auxiliary information from a class to intuit the existance of - more classes needed for a minimal schema""" - attrs = ["auxiliaryClass", "systemAuxiliaryClass", - "possSuperiors", "systemPossSuperiors", - "subClassOf"] - res = ldb.search( - expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % o.name, - basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE, - attrs=attrs) - print "Expanding class %s\n" % o.name - assert(len(res) == 1) - msg = res[0] - for a in attrs: - if not msg.has_key(aname): - continue - list = msg[aname] - if isinstance(list, str): - list = [msg[aname]] - for name in list: - if not objectclasses.has_key(name): - print "Found new objectclass '%s'\n" % name - objectclasses[name] = Objectclass(ldb, name) - - -def add_objectclass_attributes(ldb, objectclass): - """add the must and may attributes from an objectclass to the full list - of attributes""" - attrs = ["mustContain", "systemMustContain", - "mayContain", "systemMayContain"] - for aname in attrs: - if not objectclass.has_key(aname): - continue - alist = objectclass[aname] - if isinstance(alist, str): - alist = [alist] - for a in alist: - if not attributes.has_key(a): - attributes[a] = Attribute(ldb, a) - - -def walk_dn(ldb, dn): - """process an individual record, working out what attributes it has""" - # get a list of all possible attributes for this object - attrs = ["allowedAttributes"] - try: - res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, attrs) - except LdbError, e: - print "Unable to fetch allowedAttributes for '%s' - %r\n" % (dn, e) - return - allattrs = res[0]["allowedAttributes"] - try: - res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, allattrs) - except LdbError, e: - print "Unable to fetch all attributes for '%s' - %s\n" % (dn, e) - return - msg = res[0] - for a in msg: - if not attributes.has_key(a): - attributes[a] = Attribute(ldb, a) - -def walk_naming_context(ldb, namingContext): - """walk a naming context, looking for all records""" - try: - res = ldb.search("objectClass=*", namingContext, ldb.SCOPE_DEFAULT, - ["objectClass"]) - except LdbError, e: - print "Unable to fetch objectClasses for '%s' - %s\n" % (namingContext, e) - return - for msg in res: - msg = res.msgs[r]["objectClass"] - for objectClass in msg: - if not objectclasses.has_key(objectClass): - objectclasses[objectClass] = Objectclass(ldb, objectClass) - objectclasses[objectClass].exampleDN = res.msgs[r]["dn"] - walk_dn(ldb, res.msgs[r].dn) - -def trim_objectclass_attributes(ldb, objectclass): - """trim the may attributes for an objectClass""" - # trim possibleInferiors, - # include only the classes we extracted - if objectclass.has_key("possibleInferiors"): - possinf = objectclass["possibleInferiors"] - newpossinf = [] - if isinstance(possinf, str): - possinf = [possinf] - for x in possinf: - if objectclasses.has_key(x): - newpossinf[n] = x - n+=1 - objectclass["possibleInferiors"] = newpossinf - - # trim systemMayContain, - # remove duplicates - if objectclass.has_key("systemMayContain"): - sysmay = objectclass["systemMayContain"] - newsysmay = [] - if isinstance(sysmay, str): - sysmay = [sysmay] - for x in sysmay: - if not x in newsysmay: - newsysmay.append(x) - objectclass["systemMayContain"] = newsysmay - - # trim mayContain, - # remove duplicates - if not objectclass.has_key("mayContain"): - may = objectclass["mayContain"] - newmay = [] - if isinstance(may, str): - may = [may] - for x in may: - if not x in newmay: - newmay.append(x) - objectclass["mayContain"] = newmay - -def build_objectclass(ldb, name): - """load the basic attributes of an objectClass""" - attrs = ["name"] - try: - res = ldb.search( - expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % name, - basedn=rootDse["schemaNamingContext"], scope=ldb.SCOPE_SUBTREE, - attrs=attrs) - except LdbError, e: - print "unknown class '%s'\n" % name - return None - if len(res) == 0: - print "unknown class '%s'\n" % name - return None - return Objectclass(ldb, name) - -def attribute_list(objectclass, attr1, attr2): - """form a coalesced attribute list""" - a1 = objectclass[attr1] - a2 = objectclass[attr2] - if isinstance(a1, str): - a1 = [a1] - if isinstance(a2, str): - a2 = [a2] - return a1 + a2 - -def aggregate_list(name, list): - """write out a list in aggregate form""" - if list is None: - return - print "%s ( %s )" % (name, "$ ".join(list)) - -def write_aggregate_objectclass(objectclass): - """write the aggregate record for an objectclass""" - print "objectClasses: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name) - if not objectclass.has_key('subClassOf'): - print "SUP %s " % objectclass['subClassOf'] - if objectclass.objectClassCategory == 1: - print "STRUCTURAL " - elif objectclass.objectClassCategory == 2: - print "ABSTRACT " - elif objectclass.objectClassCategory == 3: - print "AUXILIARY " - - list = attribute_list(objectclass, "systemMustContain", "mustContain") - aggregate_list("MUST", list) - - list = attribute_list(objectclass, "systemMayContain", "mayContain") - aggregate_list("MAY", list) - - print ")\n" - - -def write_aggregate_ditcontentrule(objectclass): - """write the aggregate record for an ditcontentrule""" - list = attribute_list(objectclass, "auxiliaryClass", "systemAuxiliaryClass") - if list is None: - return - - print "dITContentRules: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name) - - aggregate_list("AUX", list) - - may_list = None - must_list = None - - for c in list: - list2 = attribute_list(objectclasses[c], - "mayContain", "systemMayContain") - may_list = may_list + list2 - list2 = attribute_list(objectclasses[c], - "mustContain", "systemMustContain") - must_list = must_list + list2 - - aggregate_list("MUST", must_list) - aggregate_list("MAY", may_list) - - print ")\n" - -def write_aggregate_attribute(attrib): - """write the aggregate record for an attribute""" - print "attributeTypes: ( %s NAME '%s' SYNTAX '%s' " % ( - attrib.attributeID, attrib.name, - map_attribute_syntax(attrib.attributeSyntax)) - if attrib['isSingleValued'] == "TRUE": - print "SINGLE-VALUE " - if attrib['systemOnly'] == "TRUE": - print "NO-USER-MODIFICATION " - - print ")\n" - - -def write_aggregate(): - """write the aggregate record""" - print "dn: CN=Aggregate,${SCHEMADN}\n" - print """objectClass: top -objectClass: subSchema -objectCategory: CN=SubSchema,${SCHEMADN} -""" - if not opts.dump_subschema_auto: - return - - for objectclass in objectclasses: - write_aggregate_objectclass(objectclass) - for attr in attributes: - write_aggregate_attribute(attr) - for objectclass in objectclasses: - write_aggregate_ditcontentrule(objectclass) - -def load_list(file): - """load a list from a file""" - return open(file, 'r').splitlines() - -# get the rootDSE -res = ldb.search("", "", ldb.SCOPE_BASE) -rootDse = res[0] - -# load the list of classes we are interested in -classes = load_list(classfile) -for classname in classes: - objectclass = build_objectclass(ldb, classname) - if objectclass is not None: - objectclasses[classname] = objectclass - - -# -# expand the objectclass list as needed -# -expanded = 0 - -# so EJS do not have while nor the break statement -# cannot find any other way than doing more loops -# than necessary to recursively expand all classes -# -for inf in range(500): - for n in objectclasses: - if not n in objectclasses_expanded: - expand_objectclass(ldb, objectclasses[i]) - objectclasses_expanded.add(n) - -# -# find objectclass properties -# -for objectclass in objectclasses: - find_objectclass_properties(ldb, objectclass) - - -# -# form the full list of attributes -# -for objectclass in objectclasses: - add_objectclass_attributes(ldb, objectclass) - -# and attribute properties -for attr in attributes: - find_attribute_properties(ldb, attr) - -# -# trim the 'may' attribute lists to those really needed -# -for objectclass in objectclasses: - trim_objectclass_attributes(ldb, objectclass) - -# -# dump an ldif form of the attributes and objectclasses -# -if opts.dump_attributes: - write_ldif(attributes, attrib_attrs) -if opts.dump_classes: - write_ldif(objectclasses, class_attrs) -if opts.dump_subschema: - write_aggregate() - -if not opts.verbose: - sys.exit(0) - -# -# dump list of objectclasses -# -print "objectClasses:\n" -for objectclass in objectclasses: - print "\t%s\n" % objectclass - -print "attributes:\n" -for attr in attributes: - print "\t%s\n" % attr - -print "autocreated attributes:\n" -for attr in attributes: - if attr.autocreate: - print "\t%s\n" % i -- cgit