From 67c16e0cce41aa95af2086a51180be49ec89af58 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 8c4267f..07701d1 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 ccfc067..26e33d8 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 0a5c31d..31106d4 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 62a0b0b..f0e532e 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 20a84c3..00fe638 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 d171a43..fd67b2c 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 42c88a55..aff1409 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 196cc45..4dbe472 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 3929b90..3c132f5 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.7.4 From 72f54676279253065ecd5f939cd084341bcd33c5 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 00fe638..f67353f 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.7.4 From 0de5e24f7ea1ada5e456680a5dd886f2bf961fa9 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 f67353f..7474acb 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.7.4 From 9268fcca15063f8fc58ac9544c0e07089e0d503b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 29 May 2019 16:36:00 +1200 Subject: [PATCH 4/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/sambaundoguididx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/scripting/bin/sambaundoguididx b/source4/scripting/bin/sambaundoguididx index 7474acb..0d18282 100755 --- a/source4/scripting/bin/sambaundoguididx +++ b/source4/scripting/bin/sambaundoguididx @@ -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.7.4 From d2b450e575c8b0b511fe31eb33e687d2db4a6e40 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Mon, 20 May 2019 16:19:51 +1200 Subject: [PATCH 5/6] ldb: ldbdump key and pack format version comments For testing we need to know the actual KV level key of records and each record's pack format version. This patch makes ldbdump add comments with that info. We will parse it out in python tests. Signed-off-by: Aaron Haslett Reviewed-by: Andrew Bartlett Reviewed-by: Gary Lockyer Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Wed May 22 05:58:17 UTC 2019 on sn-devel-184 --- lib/ldb/tools/ldbdump.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/ldb/tools/ldbdump.c b/lib/ldb/tools/ldbdump.c index a466e49..09b4fe0 100644 --- a/lib/ldb/tools/ldbdump.c +++ b/lib/ldb/tools/ldbdump.c @@ -36,6 +36,26 @@ static struct ldb_context *ldb; bool show_index = false; bool validate_contents = false; +static void print_data(TDB_DATA d) +{ + unsigned char *p = (unsigned char *)d.dptr; + int len = d.dsize; + while (len--) { + if (isprint(*p) && !strchr("\"\\", *p)) { + fputc(*p, stdout); + } else { + printf("\\%02X", *p); + } + p++; + } +} + +static unsigned int pull_uint32(uint8_t *p) +{ + return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); +} + + static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *state) { int ret, i, j; @@ -79,6 +99,10 @@ static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA _dbuf, void *sta } } + printf("# key: "); + print_data(key); + printf("\n# pack format: %#010x\n", pull_uint32(_dbuf.dptr)); + if (!validate_contents || ldb_dn_is_special(msg->dn)) { ldb_ldif_write_file(ldb, stdout, &ldif); TALLOC_FREE(msg); -- 2.7.4 From b7b82eb8386ee8b5e046a2003de31974ab4b9fd3 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 --- python/samba/tests/blackbox/undoguididx.py | 107 +++++++++++++++++++++++++++++ source4/selftest/tests.py | 2 + 2 files changed, 109 insertions(+) create mode 100644 python/samba/tests/blackbox/undoguididx.py diff --git a/python/samba/tests/blackbox/undoguididx.py b/python/samba/tests/blackbox/undoguididx.py new file mode 100644 index 0000000..b4e0179 --- /dev/null +++ b/python/samba/tests/blackbox/undoguididx.py @@ -0,0 +1,107 @@ +# Blackbox tests for sambaundoguididx +# +# 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/sambaundoguididx") + + +class DowngradeTest(BlackboxTestCase): + """Test that sambaundoguididx 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 sambaundoguididx replaces all GUID keys with DN keys + def test_undo_guid_idx(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 sambaundoguididx") + + 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 30fedd9..fddbf83 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.undoguididx") + 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.7.4