diff options
Diffstat (limited to 'source4/scripting/bin/minschema')
-rwxr-xr-x | source4/scripting/bin/minschema | 200 |
1 files changed, 93 insertions, 107 deletions
diff --git a/source4/scripting/bin/minschema b/source4/scripting/bin/minschema index e7d7ed4979..c860495e96 100755 --- a/source4/scripting/bin/minschema +++ b/source4/scripting/bin/minschema @@ -3,9 +3,10 @@ # work out the minimal schema for a set of objectclasses # +import base64 import optparse - -import os, sys +import os +import sys # Find right directory when running from source tree sys.path.insert(0, "bin/python") @@ -54,10 +55,10 @@ if len(args) != 2: lp_ctx = sambaopts.get_loadparm() creds = credopts.get_credentials(lp_ctx) -ldb = Ldb(url, credentials=creds) +ldb = Ldb(url, credentials=creds, lp=lp_ctx) -objectclasses = [] -attributes = [] +objectclasses = {} +attributes = {} objectclasses_expanded = set() @@ -71,7 +72,6 @@ class_attrs = ["objectClass", "mustContain", "auxiliaryClass", "rDNAttID", - "showInAdvancedViewOnly", "adminDisplayName", "adminDescription", "objectClassCategory", @@ -103,7 +103,6 @@ attrib_attrs = ["objectClass", "rangeUpper", "mAPIID", "linkID", - "showInAdvancedViewOnly", "adminDisplayName", "oMObjectClass", "adminDescription", @@ -136,24 +135,25 @@ attrib_attrs = ["objectClass", def get_object_cn(ldb, name): attrs = ["cn"] - - res = ldb.search("(ldapDisplayName=%s)" % name, rootDse["schemaNamingContext"], SCOPE_SUBTREE, attrs) + res = ldb.search(expression="(ldapDisplayName=%s)" % name, base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE, attrs=attrs) assert len(res) == 1 - return res[0]["cn"] -class Objectclass: + +class Objectclass(dict): + def __init__(self, ldb, name): """create an objectclass object""" self.name = name - self.cn = get_object_cn(ldb, name) + self["cn"] = get_object_cn(ldb, name) + +class Attribute(dict): -class Attribute: def __init__(self, ldb, name): """create an attribute object""" self.name = name - self.cn = get_object_cn(ldb, name) + self["cn"] = get_object_cn(ldb, name) syntaxmap = dict() @@ -180,36 +180,38 @@ 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): + if s in list(syntaxmap): return syntaxmap[s] return s def fix_dn(dn): """fix a string DN to use ${SCHEMADN}""" - return dn.replace(rootDse["schemaNamingContext"], "${SCHEMADN}") + return dn.replace(rootDse["schemaNamingContext"][0], "${SCHEMADN}") def write_ldif_one(o, attrs): """dump an object as ldif""" - print "dn: CN=%s,${SCHEMADN}\n" % o["cn"] + print "dn: CN=%s,${SCHEMADN}" % 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" + value = fix_dn(j) + if a == "oMObjectClass": + print "%s:: %s" % (a, base64.b64encode(value)) + elif a.endswith("GUID"): + print "%s: %s" % (a, ldb.schema_format_value(a, value)) + else: + print "%s: %s" % (a, value) + print "" + def write_ldif(o, attrs): """dump an array of objects as ldif""" - for i in o: + for n, i in o.items(): write_ldif_one(i, attrs) @@ -225,7 +227,7 @@ def find_objectclass_properties(ldb, o): """the properties of an objectclass""" res = ldb.search( expression="(ldapDisplayName=%s)" % o.name, - base=rootDse["schemaNamingContext"], scope=SCOPE_SUBTREE, attrs=class_attrs) + base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE, attrs=class_attrs) assert(len(res) == 1) msg = res[0] for a in msg: @@ -235,15 +237,11 @@ def find_attribute_properties(ldb, o): """find the properties of an attribute""" res = ldb.search( expression="(ldapDisplayName=%s)" % o.name, - base=rootDse["schemaNamingContext"], scope=SCOPE_SUBTREE, + base=rootDse["schemaNamingContext"][0], scope=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] @@ -254,15 +252,15 @@ def find_objectclass_auto(ldb, o): return testdn = create_testdn(o.exampleDN) - print "testdn is '%s'\n" % testdn + print "testdn is '%s'" % 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 + print "error adding %s: %s" % (o.name, e) + print "%s" % ldif return res = ldb.search(base=testdn, scope=ldb.SCOPE_BASE) @@ -280,20 +278,20 @@ def expand_objectclass(ldb, o): "subClassOf"] res = ldb.search( expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % o.name, - base=rootDse["schemaNamingContext"], scope=SCOPE_SUBTREE, + base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE, attrs=attrs) - print "Expanding class %s\n" % o.name + print >>sys.stderr, "Expanding class %s" % o.name assert(len(res) == 1) msg = res[0] - for a in attrs: - if not msg.has_key(aname): + for aname in attrs: + if not aname in msg: 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 + print >>sys.stderr, "Found new objectclass '%s'" % name objectclasses[name] = Objectclass(ldb, name) @@ -320,13 +318,13 @@ def walk_dn(ldb, dn): try: res = ldb.search("objectClass=*", dn, SCOPE_BASE, attrs) except LdbError, e: - print "Unable to fetch allowedAttributes for '%s' - %r\n" % (dn, e) + print >>sys.stderr, "Unable to fetch allowedAttributes for '%s' - %r" % (dn, e) return allattrs = res[0]["allowedAttributes"] try: res = ldb.search("objectClass=*", dn, SCOPE_BASE, allattrs) except LdbError, e: - print "Unable to fetch all attributes for '%s' - %s\n" % (dn, e) + print >>sys.stderr, "Unable to fetch all attributes for '%s' - %s" % (dn, e) return msg = res[0] for a in msg: @@ -339,7 +337,7 @@ def walk_naming_context(ldb, namingContext): res = ldb.search("objectClass=*", namingContext, SCOPE_DEFAULT, ["objectClass"]) except LdbError, e: - print "Unable to fetch objectClasses for '%s' - %s\n" % (namingContext, e) + print >>sys.stderr, "Unable to fetch objectClasses for '%s' - %s" % (namingContext, e) return for msg in res: msg = res.msgs[r]["objectClass"] @@ -356,12 +354,9 @@ def trim_objectclass_attributes(ldb, objectclass): 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 + newpossinf.append(x) objectclass["possibleInferiors"] = newpossinf # trim systemMayContain, @@ -369,8 +364,6 @@ def trim_objectclass_attributes(ldb, objectclass): 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) @@ -378,7 +371,7 @@ def trim_objectclass_attributes(ldb, objectclass): # trim mayContain, # remove duplicates - if not objectclass.has_key("mayContain"): + if objectclass.has_key("mayContain"): may = objectclass["mayContain"] newmay = [] if isinstance(may, str): @@ -388,71 +381,65 @@ def trim_objectclass_attributes(ldb, objectclass): 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, - base=rootDse["schemaNamingContext"], scope=SCOPE_SUBTREE, - attrs=attrs) - except LdbError, e: - print "unknown class '%s'\n" % name - return None + res = ldb.search( + expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % name, + base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE, + attrs=attrs) if len(res) == 0: - print "unknown class '%s'\n" % name + print >>sys.stderr, "unknown class '%s'" % 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] + a1 = list(objectclass.get(attr1, [])) + a2 = list(objectclass.get(attr2, [])) 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)) + if list == []: + return "" + return " %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) + line = "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 " + line += "SUP %s" % objectclass['subClassOf'] + if objectclass["objectClassCategory"] == 1: + line += "STRUCTURAL" + elif objectclass["objectClassCategory"] == 2: + line += "ABSTRACT" + elif objectclass["objectClassCategory"] == 3: + line += "AUXILIARY" list = attribute_list(objectclass, "systemMustContain", "mustContain") - aggregate_list("MUST", list) + line += aggregate_list("MUST", list) list = attribute_list(objectclass, "systemMayContain", "mayContain") - aggregate_list("MAY", list) + line += aggregate_list("MAY", list) - print ")\n" + print line + " )" def write_aggregate_ditcontentrule(objectclass): """write the aggregate record for an ditcontentrule""" list = attribute_list(objectclass, "auxiliaryClass", "systemAuxiliaryClass") - if list is None: + if list == []: return - print "dITContentRules: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name) + line = "dITContentRules: ( %s NAME '%s'" % (objectclass["governsID"], objectclass.name) - aggregate_list("AUX", list) + line += aggregate_list("AUX", list) - may_list = None - must_list = None + may_list = [] + must_list = [] for c in list: list2 = attribute_list(objectclasses[c], @@ -462,44 +449,43 @@ def write_aggregate_ditcontentrule(objectclass): "mustContain", "systemMustContain") must_list = must_list + list2 - aggregate_list("MUST", must_list) - aggregate_list("MAY", may_list) + line += aggregate_list("MUST", must_list) + line += aggregate_list("MAY", may_list) - print ")\n" + print line + " )" 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 " + line = "attributeTypes: ( %s NAME '%s' SYNTAX '%s' " % ( + attrib["attributeID"], attrib.name, + map_attribute_syntax(attrib["attributeSyntax"])) + if attrib.get('isSingleValued') == "TRUE": + line += "SINGLE-VALUE " + if attrib.get('systemOnly') == "TRUE": + line += "NO-USER-MODIFICATION " - print ")\n" + print line + ")" def write_aggregate(): """write the aggregate record""" - print "dn: CN=Aggregate,${SCHEMADN}\n" + print "dn: CN=Aggregate,${SCHEMADN}" print """objectClass: top objectClass: subSchema -objectCategory: CN=SubSchema,${SCHEMADN} -""" +objectCategory: CN=SubSchema,${SCHEMADN}""" if not opts.dump_subschema_auto: return - for objectclass in objectclasses: + for objectclass in objectclasses.values(): write_aggregate_objectclass(objectclass) - for attr in attributes: + for attr in attributes.values(): write_aggregate_attribute(attr) - for objectclass in objectclasses: + for objectclass in objectclasses.values(): write_aggregate_ditcontentrule(objectclass) def load_list(file): """load a list from a file""" - return open(file, 'r').readlines() + return [l.strip("\n") for l in open(file, 'r').readlines()] # get the rootDSE res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext"]) @@ -523,32 +509,32 @@ expanded = 0 # than necessary to recursively expand all classes # for inf in range(500): - for n in objectclasses: + for n, o in objectclasses.items(): if not n in objectclasses_expanded: - expand_objectclass(ldb, objectclasses[i]) + expand_objectclass(ldb, o) objectclasses_expanded.add(n) # # find objectclass properties # -for objectclass in objectclasses: +for name, objectclass in objectclasses.items(): find_objectclass_properties(ldb, objectclass) # # form the full list of attributes # -for objectclass in objectclasses: +for name, objectclass in objectclasses.items(): add_objectclass_attributes(ldb, objectclass) # and attribute properties -for attr in attributes: +for name, attr in attributes.items(): find_attribute_properties(ldb, attr) # # trim the 'may' attribute lists to those really needed # -for objectclass in objectclasses: +for name, objectclass in objectclasses.items(): trim_objectclass_attributes(ldb, objectclass) # |