From b7f7a149189c6345275aade0908b854f1ce5e959 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Sat, 9 Mar 2019 13:48:29 +1300 Subject: [PATCH 1/6] s4/scripting: MORE py3 compatible print functions BUG: https://bugzilla.samba.org/show_bug.cgi?id=13978 Signed-off-by: Douglas Bagnall Reviewed-by: Andrew Bartlett (cherry picked from commit 561b654bc5bc2f5e614c5c2ab378193ca94d481a) --- source4/scripting/bin/autoidl | 19 +++++----- source4/scripting/bin/fullschema | 9 ++--- source4/scripting/bin/get-descriptors | 9 ++--- source4/scripting/bin/minschema | 47 +++++++++++++------------ source4/scripting/bin/sambaundoguididx | 8 +++-- source4/scripting/bin/smbstatus | 19 +++++----- source4/scripting/devel/addlotscontacts | 4 +-- source4/scripting/devel/crackname | 10 +++--- source4/scripting/devel/getncchanges | 8 ++--- 9 files changed, 71 insertions(+), 62 deletions(-) diff --git a/source4/scripting/bin/autoidl b/source4/scripting/bin/autoidl index 8c4267f90fb..07701d1a705 100755 --- a/source4/scripting/bin/autoidl +++ b/source4/scripting/bin/autoidl @@ -17,6 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +from __future__ import print_function import sys @@ -107,25 +108,25 @@ class Function: if base_request is None: raise Exception("Unable to determine base size for opnum %d" % self.opnum) - print "\tBase request is %r" % base_request + print("\tBase request is %r" % base_request) decision_byte_map = map(lambda x: self.check_decision_byte(base_request, x), range(len(base_request))) - print decision_byte_map + print(decision_byte_map) # find pointers possible_pointers = map(all, [decision_byte_map[i*4:(i+1)*4] for i in range(int(len(base_request)/4))]) - print possible_pointers + print(possible_pointers) pointer_deferrant_bases = map( lambda x: self.find_deferrant_data(base_request, x) if possible_pointers[x] else None, range(len(possible_pointers))) - print pointer_deferrant_bases + print(pointer_deferrant_bases) if len(sys.argv) < 3: - print "Usage: autoidl []" + print("Usage: autoidl []") sys.exit(1) (binding, uuid) = sys.argv[1:3] @@ -147,15 +148,15 @@ if version is None: else: conn = ClientConnection(binding, (uuid, version)) -print "Figuring out number of connections...", +print("Figuring out number of connections... ", end='') num_funcs = find_num_funcs(conn) -print "%d" % num_funcs +print("%d" % num_funcs) # Figure out the syntax for each one for i in range(num_funcs): - print "Function %d" % i + print("Function %d" % i) data = Function(conn, i) try: data.find_idl() except Exception as e: - print "Error: %r" % e + print("Error: %r" % e) diff --git a/source4/scripting/bin/fullschema b/source4/scripting/bin/fullschema index ccfc0678d48..26e33d8059f 100755 --- a/source4/scripting/bin/fullschema +++ b/source4/scripting/bin/fullschema @@ -2,6 +2,7 @@ # # Works out the full schema # +from __future__ import print_function import base64 import optparse @@ -147,12 +148,12 @@ def write_ldif_one(o, attrs): value = fix_dn(j) if a != "cn": if a == "oMObjectClass": - print "%s:: %s" % (a, base64.b64encode(value)).decode('utf8') + print("%s:: %s" % (a, base64.b64encode(value)).decode('utf8')) elif a.endswith("GUID"): - print "%s: %s" % (a, ldb.schema_format_value(a, value)) + print("%s: %s" % (a, ldb.schema_format_value(a, value))) else: - print "%s: %s" % (a, value) - print "" + print("%s: %s" % (a, value)) + print() # get the rootDSE diff --git a/source4/scripting/bin/get-descriptors b/source4/scripting/bin/get-descriptors index 0a5c31d0103..31106d434b0 100755 --- a/source4/scripting/bin/get-descriptors +++ b/source4/scripting/bin/get-descriptors @@ -26,6 +26,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +from __future__ import print_function import optparse import sys @@ -97,12 +98,12 @@ class DescrGetter: l = line[i * length:((i + 1) * length)] else: l = " " + line[(i * length):((i + 1) * length)] - print l - print "\n" + print(l) + print("\n") def write_as_sddl(self, dn, descr): - print dn - print descr + "\n" + print(dn) + print(descr + "\n") def read_descr_by_base(self, search_base): res = self.samdb.search(base=search_base + self.local_domain, expression="(objectClass=*)", scope=SCOPE_SUBTREE, attrs=["nTSecurityDescriptor"]) diff --git a/source4/scripting/bin/minschema b/source4/scripting/bin/minschema index 62a0b0b00f0..f0e532ec9bb 100755 --- a/source4/scripting/bin/minschema +++ b/source4/scripting/bin/minschema @@ -2,7 +2,7 @@ # # Works out the minimal schema for a set of objectclasses # - +from __future__ import print_function import base64 import optparse import sys @@ -251,15 +251,15 @@ def find_objectclass_auto(ldb, o): return testdn = create_testdn(o.exampleDN) - print "testdn is '%s'" % testdn + print("testdn is '%s'" % testdn) ldif = "dn: " + testdn ldif += "\nobjectClass: " + o.name try: ldb.add(ldif) except LdbError as e: - print "error adding %s: %s" % (o.name, e) - print "%s" % ldif + print("error adding %s: %s" % (o.name, e)) + print("%s" % ldif) return res = ldb.search(base=testdn, scope=ldb.SCOPE_BASE) @@ -279,7 +279,7 @@ def expand_objectclass(ldb, o): expression="(&(objectClass=classSchema)(ldapDisplayName=%s))" % o.name, base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE, attrs=attrs) - print >>sys.stderr, "Expanding class %s" % o.name + print("Expanding class %s" % o.name, file=sys.stderr) assert(len(res) == 1) msg = res[0] for aname in attrs: @@ -290,7 +290,7 @@ def expand_objectclass(ldb, o): list = [msg[aname]] for name in list: if not objectclasses.has_key(name): - print >>sys.stderr, "Found new objectclass '%s'" % name + print("Found new objectclass '%s'" % name, file=sys.stderr) objectclasses[name] = Objectclass(ldb, name) @@ -317,13 +317,15 @@ def walk_dn(ldb, dn): try: res = ldb.search("objectClass=*", dn, SCOPE_BASE, attrs) except LdbError as e: - print >>sys.stderr, "Unable to fetch allowedAttributes for '%s' - %r" % (dn, e) + print("Unable to fetch allowedAttributes for '%s' - %r" % (dn, e), + file=sys.stderr) return allattrs = res[0]["allowedAttributes"] try: res = ldb.search("objectClass=*", dn, SCOPE_BASE, allattrs) except LdbError as e: - print >>sys.stderr, "Unable to fetch all attributes for '%s' - %s" % (dn, e) + print("Unable to fetch all attributes for '%s' - %s" % (dn, e), + file=sys.stderr) return msg = res[0] for a in msg: @@ -336,7 +338,8 @@ def walk_naming_context(ldb, namingContext): res = ldb.search("objectClass=*", namingContext, SCOPE_DEFAULT, ["objectClass"]) except LdbError as e: - print >>sys.stderr, "Unable to fetch objectClasses for '%s' - %s" % (namingContext, e) + print("Unable to fetch objectClasses for '%s' - %s" % (namingContext, e), + file=sys.stderr) return for msg in res: msg = res.msgs[r]["objectClass"] @@ -389,7 +392,7 @@ def build_objectclass(ldb, name): base=rootDse["schemaNamingContext"][0], scope=SCOPE_SUBTREE, attrs=attrs) if len(res) == 0: - print >>sys.stderr, "unknown class '%s'" % name + print("unknown class '%s'" % name, file=sys.stderr) return None return Objectclass(ldb, name) @@ -424,7 +427,7 @@ def write_aggregate_objectclass(objectclass): list = attribute_list(objectclass, "systemMayContain", "mayContain") line += aggregate_list("MAY", list) - print line + " )" + print(line + " )") def write_aggregate_ditcontentrule(objectclass): @@ -451,7 +454,7 @@ def write_aggregate_ditcontentrule(objectclass): line += aggregate_list("MUST", must_list) line += aggregate_list("MAY", may_list) - print line + " )" + print(line + " )") def write_aggregate_attribute(attrib): """write the aggregate record for an attribute""" @@ -463,15 +466,15 @@ def write_aggregate_attribute(attrib): if attrib.get('systemOnly') == "TRUE": line += "NO-USER-MODIFICATION " - print line + ")" + print(line + ")") def write_aggregate(): """write the aggregate record""" - print "dn: CN=Aggregate,${SCHEMADN}" - print """objectClass: top + 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 @@ -552,15 +555,15 @@ if not opts.verbose: # # dump list of objectclasses # -print "objectClasses:\n" +print("objectClasses:\n") for objectclass in objectclasses: - print "\t%s\n" % objectclass + print("\t%s\n" % objectclass) -print "attributes:\n" +print("attributes:\n") for attr in attributes: - print "\t%s\n" % attr + print("\t%s\n" % attr) -print "autocreated attributes:\n" +print("autocreated attributes:\n") for attr in attributes: if attr.autocreate: - print "\t%s\n" % i + print("\t%s\n" % i) diff --git a/source4/scripting/bin/sambaundoguididx b/source4/scripting/bin/sambaundoguididx index 20a84c34618..00fe63897b4 100755 --- a/source4/scripting/bin/sambaundoguididx +++ b/source4/scripting/bin/sambaundoguididx @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from __future__ import print_function import optparse import sys @@ -73,11 +74,12 @@ samdb.transaction_commit() print("Re-opening with the full DB stack") samdb = SamDB(url=url, lp=lp_ctx) -print "Re-triggering another re-index" +print("Re-triggering another re-index") chk = dbcheck(samdb) chk.reindex_database() -print "Your database has been downgraded to DN-based index values." +print("Your database has been downgraded to DN-based index values.") -print "NOTE: Any use of a Samba 4.8 tool including ldbsearch will auto-upgrade back to GUID index mode" +print("NOTE: Any use of a Samba 4.8 tool including ldbsearch will " + "auto-upgrade back to GUID index mode") diff --git a/source4/scripting/bin/smbstatus b/source4/scripting/bin/smbstatus index d171a433a30..fd67b2ca691 100755 --- a/source4/scripting/bin/smbstatus +++ b/source4/scripting/bin/smbstatus @@ -8,7 +8,7 @@ # Copyright Andrew Tridgell 2005 # Released under the GNU GPL version 3 or later # - +from __future__ import print_function import os, sys # make sure the script dies immediately when hitting control-C, @@ -40,25 +40,26 @@ def show_tcons(open_connection): """show open tree connects""" conn = open_connection("smb_server") tcons = next(conn.smbsrv_information(irpc.SMBSRV_INFO_TCONS)) - print "Share Client Connected at" - print "-" * 79 + print("Share Client Connected at") + print("-" * 79) for tcon in tcons: - print "%-30s %16s %s" % (tcon.share_name, tcon.client_ip, sys.httptime(tcon.connect_time)) + print("%-30s %16s %s" % + (tcon.share_name, tcon.client_ip, sys.httptime(tcon.connect_time))) def show_nbt(open_connection): """show nbtd information""" conn = open_connection("nbt_server") stats = next(conn.nbtd_information(irpc.NBTD_INFO_STATISTICS)) - print "NBT server statistics:" + print("NBT server statistics:") fields = [("total_received", "Total received"), ("total_sent", "Total sent"), ("query_count", "Query count"), ("register_count", "Register count"), ("release_count", "Release count")] for (field, description) in fields: - print "\t%s:\t%s" % (description, getattr(stats, field)) - print + print("\t%s:\t%s" % (description, getattr(stats, field))) + print() parser = optparse.OptionParser("%s [options]" % sys.argv[0]) sambaopts = options.SambaOptions(parser) @@ -71,7 +72,7 @@ opts, args = parser.parse_args() lp = sambaopts.get_loadparm() -print "%s" % lp.get("server string") +print("%s" % lp.get("server string")) messaging_path = (opts.messaging_path or os.path.join(lp.get("private dir"), "smbd.tmp", "messaging")) @@ -85,7 +86,7 @@ else: conn = open_connection("smb_server") except RuntimeError, (num, msg): if msg == 'NT_STATUS_OBJECT_NAME_NOT_FOUND': - print "No active connections" + print("No active connections") else: show_sessions(conn) show_tcons(conn) diff --git a/source4/scripting/devel/addlotscontacts b/source4/scripting/devel/addlotscontacts index 42c88a5540a..aff14092021 100644 --- a/source4/scripting/devel/addlotscontacts +++ b/source4/scripting/devel/addlotscontacts @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - +from __future__ import print_function __docformat__ = "restructuredText" @@ -88,7 +88,7 @@ if __name__ == '__main__': "objectClass") if count !=0 and (count % increment) == 0: - print "Added contacts: %d" % count + print("Added contacts: %d" % count) ldbs.sam.add(msg) count += 1 diff --git a/source4/scripting/devel/crackname b/source4/scripting/devel/crackname index 196cc45d5c9..4dbe47227aa 100755 --- a/source4/scripting/devel/crackname +++ b/source4/scripting/devel/crackname @@ -3,7 +3,7 @@ # Copyright Matthieu Patou 2011 # script to call a DRSUAPI crackname # this is useful for plugfest testing and replication debug - +from __future__ import print_function import sys from optparse import OptionParser @@ -71,8 +71,8 @@ if __name__ == "__main__": req.names = [names] (result, ctr) = drs.DsCrackNames(drs_handle, 1, req) - print "# of result = %d" %ctr.count + print("# of result = %d" %ctr.count) if ctr.count: - print "status = %d" % ctr.array[0].status - print "result name = %s" % ctr.array[0].result_name - print "domain = %s" % ctr.array[0].dns_domain_name + print("status = %d" % ctr.array[0].status) + print("result name = %s" % ctr.array[0].result_name) + print("domain = %s" % ctr.array[0].dns_domain_name) diff --git a/source4/scripting/devel/getncchanges b/source4/scripting/devel/getncchanges index 3929b906a90..3c132f5f0d3 100755 --- a/source4/scripting/devel/getncchanges +++ b/source4/scripting/devel/getncchanges @@ -2,7 +2,7 @@ # script to call a DRS GetNCChanges from the command line # this is useful for plugfest testing - +from __future__ import print_function import sys from optparse import OptionParser @@ -98,17 +98,17 @@ if __name__ == "__main__": dest_dsa = opts.dest_dsa if not dest_dsa: - print "no dest_dsa specified trying to figure out from ldap" + print("no dest_dsa specified trying to figure out from ldap") msgs = samdb.search(controls=["search_options:1:2"], expression='(objectclass=ntdsdsa)') if len(msgs) == 1: dest_dsa = str(ndr_unpack(misc.GUID, msgs[0]["invocationId"][0])) - print "Found this dsa: %s" % dest_dsa + print("Found this dsa: %s" % dest_dsa) else: # TODO fixme pass if not dest_dsa: - print "Unable to find the dest_dsa automatically please specify it" + print("Unable to find the dest_dsa automatically please specify it") import sys sys.exit(1) -- 2.17.1 From 6c507ec92f8daee76e4d34fded9b15484f67bb5d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 20 May 2019 16:29:10 +1200 Subject: [PATCH 2/6] sambaundoguididx: Add flags=ldb.FLG_DONT_CREATE_DB and port to Python3 In py3 we need to add an extra str() around the returned ldb value to enable .split() to be used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13978 Signed-off-by: Andrew Bartlett Reviewed By: Noel Power Autobuild-User(master): Noel Power Autobuild-Date(master): Thu May 23 14:25:52 UTC 2019 on sn-devel-184 (cherry picked from commit 1a9da378a1505daff498be6d6355debd73526a1a) --- source4/scripting/bin/sambaundoguididx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/source4/scripting/bin/sambaundoguididx b/source4/scripting/bin/sambaundoguididx index 00fe63897b4..f67353ff361 100755 --- a/source4/scripting/bin/sambaundoguididx +++ b/source4/scripting/bin/sambaundoguididx @@ -34,7 +34,9 @@ if opts.H is None: else: url = opts.H -samdb = ldb.Ldb(url=url, options=["modules:"]) +samdb = ldb.Ldb(url=url, + flags=ldb.FLG_DONT_CREATE_DB, + options=["modules:"]) partitions = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE, @@ -58,10 +60,11 @@ privatedir = os.path.dirname(url) dbs = [] for part in partitions[0]['partition']: - tdbname = part.split(":")[1] - tdbpath = os.path.join(privatedir, tdbname) - - db = ldb.Ldb(url=tdbpath, options=["modules:"]) + dbname = str(part).split(":")[1] + dbpath = os.path.join(privatedir, dbname) + db = ldb.Ldb(url="ldb://" + dbpath, + options=["modules:"], + flags=ldb.FLG_DONT_CREATE_DB) db.transaction_start() db.modify(modmsg) dbs.append(db) @@ -73,7 +76,8 @@ samdb.transaction_commit() print("Re-opening with the full DB stack") samdb = SamDB(url=url, - lp=lp_ctx) + flags=ldb.FLG_DONT_CREATE_DB, + lp=lp_ctx) print("Re-triggering another re-index") chk = dbcheck(samdb) -- 2.17.1 From 62d676ca00b6e769e511efc14c96daa59c72e630 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 20 May 2019 16:29:10 +1200 Subject: [PATCH 3/6] sambaundoguididx: fix for -s Quick fix running this script with -s instead of -H. samdb_url() returns a url with a protocol prefix, which causes issues further down in the script. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13978 Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit 40ca8ed5a152ae7c5ec039649c09a037a20a4143) --- source4/scripting/bin/sambaundoguididx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source4/scripting/bin/sambaundoguididx b/source4/scripting/bin/sambaundoguididx index f67353ff361..7474acb2cab 100755 --- a/source4/scripting/bin/sambaundoguididx +++ b/source4/scripting/bin/sambaundoguididx @@ -30,7 +30,7 @@ lp_ctx = sambaopts.get_loadparm() lp_ctx.set("dsdb:guid index", "false") if opts.H is None: - url = lp_ctx.samdb_url() + url = lp_ctx.private_path("sam.ldb") else: url = opts.H @@ -62,7 +62,9 @@ dbs = [] for part in partitions[0]['partition']: dbname = str(part).split(":")[1] dbpath = os.path.join(privatedir, dbname) - db = ldb.Ldb(url="ldb://" + dbpath, + if os.path.isfile(dbpath): + dbpath = "ldb://" + dbpath + db = ldb.Ldb(url=dbpath, options=["modules:"], flags=ldb.FLG_DONT_CREATE_DB) db.transaction_start() -- 2.17.1 From 5b856c55b24beca9fc41fc60970aff29c1ffd447 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Fri, 24 May 2019 14:37:50 +1200 Subject: [PATCH 4/6] sambaundoguididx: renamed to downgradedatabase In forthcoming commits we're going to repurpose this script to do an entire downgrade of a database, disabling all new database features. downgradedatabase is a more appropriate name. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13978 Signed-off-by: Aaron Haslett Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit c0b679f6a3f21e262d03bf38ea63900d30c29bb5) --- .../scripting/bin/{sambaundoguididx => sambadowngradedatabase} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename source4/scripting/bin/{sambaundoguididx => sambadowngradedatabase} (100%) diff --git a/source4/scripting/bin/sambaundoguididx b/source4/scripting/bin/sambadowngradedatabase similarity index 100% rename from source4/scripting/bin/sambaundoguididx rename to source4/scripting/bin/sambadowngradedatabase -- 2.17.1 From c9b1680d953c117bd300cec477924ba5b6dfa928 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 29 May 2019 16:36:00 +1200 Subject: [PATCH 5/6] sambadowngradedatabase: Add "or later" to warning about using tools from Samba 4.8 BUG: https://bugzilla.samba.org/show_bug.cgi?id=13978 Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit 09f2a187b3d8c161e2c11588499b3256a9dbcc95) --- source4/scripting/bin/sambadowngradedatabase | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/scripting/bin/sambadowngradedatabase b/source4/scripting/bin/sambadowngradedatabase index 7474acb2cab..0d182820902 100755 --- a/source4/scripting/bin/sambadowngradedatabase +++ b/source4/scripting/bin/sambadowngradedatabase @@ -87,5 +87,5 @@ chk.reindex_database() print("Your database has been downgraded to DN-based index values.") -print("NOTE: Any use of a Samba 4.8 tool including ldbsearch will " +print("NOTE: Any use of a Samba 4.8 or later tool including ldbsearch will " "auto-upgrade back to GUID index mode") -- 2.17.1 From 7da4107d20322e6f22608dead68636784cac2952 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Thu, 23 May 2019 13:21:19 +1200 Subject: [PATCH 6/6] downgradedatabase: blackbox test This test confirms that running downgradedatabase causes all GUID keys to be replaced with DN keys at the KV level BUG: https://bugzilla.samba.org/show_bug.cgi?id=13978 Signed-off-by: Aaron Haslett Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (backport from commit 74d15c9bf76f0a2fb5fa7b7b1d80971d10c4fe45, ab376a97c972d2d5ebfb912ed90664c787860dc8 and 56400153c8c7052fe319f273c30c6d59556102dc) ab376a97c972d2d5ebfb912ed90664c787860dc8 was: selftest: Specifically remove files generated by provision Signed-off-by: Andrew Bartlett Reviewed-by: Douglas Bagnall 56400153c8c7052fe319f273c30c6d59556102dc was: Signed-off-by: Andrew Bartlett Reviewed-by: Douglas Bagnall --- .../samba/tests/blackbox/downgradedatabase.py | 107 ++++++++++++++++++ source4/selftest/tests.py | 2 + 2 files changed, 109 insertions(+) create mode 100644 python/samba/tests/blackbox/downgradedatabase.py diff --git a/python/samba/tests/blackbox/downgradedatabase.py b/python/samba/tests/blackbox/downgradedatabase.py new file mode 100644 index 00000000000..32e73f3b86d --- /dev/null +++ b/python/samba/tests/blackbox/downgradedatabase.py @@ -0,0 +1,107 @@ +# Blackbox tests for sambadowngradedatabase +# +# Copyright (C) Catalyst IT Ltd. 2019 +# +# 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 . +# +from __future__ import print_function +from samba.tests import BlackboxTestCase +import os +import ldb +import shutil +from subprocess import check_output +from samba.samdb import SamDB + +COMMAND = os.path.join(os.path.dirname(__file__), + "../../../../../source4/scripting/bin/sambadowngradedatabase") + + +class DowngradeTest(BlackboxTestCase): + """Test that sambadowngradedatabase downgrades the samba database""" + backend = 'tdb' + + def setUp(self): + super(DowngradeTest, self).setUp() + + prov_cmd = "samba-tool domain provision " +\ + "--domain FOO --realm foo.example.com " +\ + "--targetdir {self.tempdir} " +\ + "--backend-store {self.backend} " +\ + "--host-name downgradetest " +\ + "--option=\"vfs objects=fake_acls xattr_tdb\"" + prov_cmd = prov_cmd.format(self=self) + self.check_run(prov_cmd, "Provisioning for downgrade") + + private_dir = os.path.join(self.tempdir, "private") + self.sam_path = os.path.join(private_dir, "sam.ldb") + self.ldb = ldb.Ldb(self.sam_path, options=["modules:"]) + + partitions = self.ldb.search(base="@PARTITION", + scope=ldb.SCOPE_BASE, + attrs=["partition"]) + partitions = partitions[0]['partition'] + partitions = [str(p).split(":")[1] for p in partitions] + self.dbs = [os.path.join(private_dir, p) + for p in partitions] + self.dbs.append(self.sam_path) + + def tearDown(self): + shutil.rmtree(os.path.join(self.tempdir, "private")) + shutil.rmtree(os.path.join(self.tempdir, "etc")) + shutil.rmtree(os.path.join(self.tempdir, "state")) + shutil.rmtree(os.path.join(self.tempdir, "bind-dns")) + shutil.rmtree(os.path.join(self.tempdir, "msg.lock")) + os.unlink(os.path.join(self.tempdir, "names.tdb")) + os.unlink(os.path.join(self.tempdir, "gencache.tdb")) + super(DowngradeTest, self).tearDown() + + # Parse out the comments above each record that ldbdump produces + # containing pack format version and KV level key for each record. + # Return all GUID keys and DN keys (without @attrs) + def ldbdump_keys_pack_formats(self): + # Get all comments from all partition dbs + comments = [] + for db in self.dbs: + dump = check_output(["bin/ldbdump", "-i", db]) + dump = dump.decode("utf-8") + dump = dump.split("\n") + comments += [s for s in dump if s.startswith("#")] + + guid_key_tag = "# key: GUID=" + guid_keys = {c[len(guid_key_tag):] for c in comments + if c.startswith(guid_key_tag)} + + dn_key_tag = "# key: DN=" + dn_keys = {c[len(dn_key_tag):] for c in comments + if c.startswith(dn_key_tag)} + + # Ignore @ attributes, they are always DN keyed + dn_keys_no_at_attrs = {d for d in dn_keys if not d.startswith("@")} + + return dn_keys_no_at_attrs, guid_keys + + # Check that sambadowngradedatabase replaces all GUID keys with DN keys + def test_downgrade_database(self): + dn_keys, guid_keys = self.ldbdump_keys_pack_formats() + self.assertGreater(len(guid_keys), 20) + self.assertEqual(len(dn_keys), 0) + + num_guid_keys_before_downgrade = len(guid_keys) + + self.check_run("%s -H %s" % (COMMAND, self.sam_path), + msg="Running sambadowngradedatabase") + + dn_keys, guid_keys = self.ldbdump_keys_pack_formats() + self.assertEqual(len(guid_keys), 0) + self.assertEqual(len(dn_keys), num_guid_keys_before_downgrade) diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 5205ff44165..ca03a58f1d2 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -857,6 +857,8 @@ for env in ["ad_dc_ntvfs:local", "ad_dc:local", "promoted_dc:local"]: planoldpythontestsuite(env, "samba.tests.blackbox.smbcontrol", py3_compatible=True) +planoldpythontestsuite("none", "samba.tests.blackbox.downgradedatabase") + plantestsuite_loadlist("samba4.ldap.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba4.tokengroups.krb5.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'yes', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba4.tokengroups.ntlm.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'no', '$LOADLIST', '$LISTOPT']) -- 2.17.1