From 917905aea0cfeff53009839f70cdc9eefdcfa2c9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 12 Mar 2009 13:13:14 +1100 Subject: removed leading spaces from embedded ldif This fixes the problem with the setpassword command failing like this: Error: First line of ldif must be a dn not ' dn' --- source4/scripting/python/samba/samdb.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 614970d3ec..740806f266 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -175,10 +175,10 @@ userAccountControl: %u user_dn = res[0].dn setpw = """ - dn: %s - changetype: modify - replace: userPassword - userPassword: %s +dn: %s +changetype: modify +replace: userPassword +userPassword: %s """ % (user_dn, password) self.modify_ldif(setpw) @@ -229,12 +229,12 @@ userAccountControl: %u accountExpires = glue.unix2nttime(expiry_seconds + int(time.time())) mod = """ - dn: %s - changetype: modify - replace: userAccountControl - userAccountControl: %u - replace: accountExpires - accountExpires: %u +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +replace: accountExpires +accountExpires: %u """ % (res[0].dn, userAccountControl, accountExpires) # now change the database self.modify_ldif(mod) -- cgit From 0770028cbea5f13c0dda2b9a89803359bed66306 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 12 Mar 2009 15:13:23 +1100 Subject: fixed more embedded spaces in LDIF This one added 3 spaces to the end of any new passwords --- source4/scripting/python/samba/samdb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 740806f266..1c5a8dfcde 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -59,7 +59,7 @@ dn: CN=%s,CN=ForeignSecurityPrincipals,%s objectClass: top objectClass: foreignSecurityPrincipal description: %s - """ % (sid, domaindn, desc) +""" % (sid, domaindn, desc) # deliberately ignore errors from this, as the records may # already exist for msg in self.parse_ldif(add): @@ -179,7 +179,7 @@ dn: %s changetype: modify replace: userPassword userPassword: %s - """ % (user_dn, password) +""" % (user_dn, password) self.modify_ldif(setpw) @@ -235,7 +235,7 @@ replace: userAccountControl userAccountControl: %u replace: accountExpires accountExpires: %u - """ % (res[0].dn, userAccountControl, accountExpires) +""" % (res[0].dn, userAccountControl, accountExpires) # now change the database self.modify_ldif(mod) except: -- cgit From 483525f73c5597c0c35de4288d97f53b9d3d262e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 12 Mar 2009 15:20:25 +1100 Subject: use a base64 encoded password when changing passwords This avoids problems with embedded control characters in password changes --- source4/scripting/python/samba/samdb.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 1c5a8dfcde..b92a91e2ef 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -28,6 +28,7 @@ import ldb from samba.idmap import IDmapDB import pwd import time +import base64 __docformat__ = "restructuredText" @@ -178,8 +179,8 @@ userAccountControl: %u dn: %s changetype: modify replace: userPassword -userPassword: %s -""" % (user_dn, password) +userPassword:: %s +""" % (user_dn, base64.b64encode(password)) self.modify_ldif(setpw) -- cgit From ec9aeeab00584f4d3dfe9afb83dc1a77b8463b81 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 20 Mar 2009 01:29:31 +0100 Subject: Fix up minschema after the conversion from JavaScript. Pair programmed over the phone with Andrew :-) --- source4/scripting/bin/minschema | 165 +++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 88 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/minschema b/source4/scripting/bin/minschema index e7d7ed4979..f2dfdcb564 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() @@ -136,24 +137,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 +182,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 +229,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 +239,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 +254,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 +280,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 +320,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 +339,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 +356,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 +366,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 +373,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,30 +383,24 @@ 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): @@ -422,15 +411,15 @@ def aggregate_list(name, list): def write_aggregate_objectclass(objectclass): """write the aggregate record for an objectclass""" - print "objectClasses: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name) + 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 " + 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) @@ -438,7 +427,7 @@ def write_aggregate_objectclass(objectclass): list = attribute_list(objectclass, "systemMayContain", "mayContain") aggregate_list("MAY", list) - print ")\n" + print ")" def write_aggregate_ditcontentrule(objectclass): @@ -447,12 +436,12 @@ def write_aggregate_ditcontentrule(objectclass): if list is None: return - print "dITContentRules: ( %s NAME '%s' " % (objectclass.governsID, objectclass.name) + print "dITContentRules: ( %s NAME '%s' " % (objectclass["governsID"], objectclass.name) aggregate_list("AUX", list) - may_list = None - must_list = None + may_list = [] + must_list = [] for c in list: list2 = attribute_list(objectclasses[c], @@ -470,11 +459,11 @@ def write_aggregate_ditcontentrule(objectclass): 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": + attrib["attributeID"], attrib.name, + map_attribute_syntax(attrib["attributeSyntax"])) + if attrib.get('isSingleValued') == "TRUE": print "SINGLE-VALUE " - if attrib['systemOnly'] == "TRUE": + if attrib.get('systemOnly') == "TRUE": print "NO-USER-MODIFICATION " print ")\n" @@ -490,16 +479,16 @@ 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 +512,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) # -- cgit