summaryrefslogtreecommitdiffstats
path: root/source4/scripting/devel
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 17:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 17:47:29 +0000
commit4f5791ebd03eaec1c7da0865a383175b05102712 (patch)
tree8ce7b00f7a76baa386372422adebbe64510812d4 /source4/scripting/devel
parentInitial commit. (diff)
downloadsamba-4f5791ebd03eaec1c7da0865a383175b05102712.tar.xz
samba-4f5791ebd03eaec1c7da0865a383175b05102712.zip
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/scripting/devel')
-rw-r--r--source4/scripting/devel/addlotscontacts95
-rw-r--r--source4/scripting/devel/chgkrbtgtpass60
-rwxr-xr-xsource4/scripting/devel/chgtdcpass63
-rwxr-xr-xsource4/scripting/devel/config_base39
-rwxr-xr-xsource4/scripting/devel/crackname77
-rwxr-xr-xsource4/scripting/devel/demodirsync.py159
-rw-r--r--source4/scripting/devel/drs/fsmo.ldif.template75
-rw-r--r--source4/scripting/devel/drs/named.conf.ad.template6
-rwxr-xr-xsource4/scripting/devel/drs/revampire_ad.sh23
-rwxr-xr-xsource4/scripting/devel/drs/unvampire_ad.sh14
-rwxr-xr-xsource4/scripting/devel/drs/vampire_ad.sh28
-rw-r--r--source4/scripting/devel/drs/vars12
-rwxr-xr-xsource4/scripting/devel/enumprivs58
-rwxr-xr-xsource4/scripting/devel/getncchanges143
-rwxr-xr-xsource4/scripting/devel/nmfind15
-rwxr-xr-xsource4/scripting/devel/pfm_verify.py192
-rwxr-xr-xsource4/scripting/devel/rebuild_zone.sh109
-rwxr-xr-xsource4/scripting/devel/repl_cleartext_pwd.py412
-rwxr-xr-xsource4/scripting/devel/rodcdns43
-rwxr-xr-xsource4/scripting/devel/speedtest.py235
-rwxr-xr-xsource4/scripting/devel/tmpfs.sh16
-rw-r--r--source4/scripting/devel/watch_servers.sh14
22 files changed, 1888 insertions, 0 deletions
diff --git a/source4/scripting/devel/addlotscontacts b/source4/scripting/devel/addlotscontacts
new file mode 100644
index 0000000..9ecd16b
--- /dev/null
+++ b/source4/scripting/devel/addlotscontacts
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) Matthieu Patou <mat@matws.net> 2010
+#
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+__docformat__ = "restructuredText"
+
+
+import optparse
+import sys
+# Allow to run from s4 source directory (without installing samba)
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+from samba.credentials import DONT_USE_KERBEROS
+from samba.auth import system_session
+from samba import param
+from samba.provision import find_provision_key_parameters
+from samba.upgradehelpers import (get_paths, get_ldbs)
+from ldb import SCOPE_BASE, Message, MessageElement, Dn, FLAG_MOD_ADD
+
+parser = optparse.OptionParser("addlotscontacts [options]")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+
+(opts, args) = parser.parse_args()
+
+lp = sambaopts.get_loadparm()
+smbconf = lp.configfile
+creds = credopts.get_credentials(lp)
+creds.set_kerberos_state(DONT_USE_KERBEROS)
+
+if len(args) > 0:
+ num_contacts = int(args[0])
+else:
+ num_contacts = 10000
+
+if __name__ == '__main__':
+ paths = get_paths(param, smbconf=smbconf)
+ session = system_session()
+
+ ldbs = get_ldbs(paths, creds, session, lp)
+ ldbs.startTransactions()
+
+ names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap,
+ paths, smbconf, lp)
+
+ contactdn = "OU=Contacts,%s" % str(names.domaindn)
+ res = ldbs.sam.search(expression="(distinguishedName=%s)" % contactdn,
+ base=str(names.domaindn),
+ scope=SCOPE_BASE)
+
+ if (len(res) == 0):
+ msg = Message()
+ msg.dn = Dn(ldbs.sam, contactdn)
+ msg["objectClass"] = MessageElement("organizationalUnit", FLAG_MOD_ADD,
+ "objectClass")
+
+ ldbs.sam.add(msg)
+
+ print("Creating %d contacts" % num_contacts)
+ count = 0
+ increment = num_contacts / 10
+ if increment > 5000:
+ increment = 5000
+
+ while (count < num_contacts):
+ msg = Message()
+ msg.dn = Dn(ldbs.sam, "CN=contact%d,%s" % (count + 1, contactdn))
+ msg["objectClass"] = MessageElement("contact", FLAG_MOD_ADD,
+ "objectClass")
+
+ if count !=0 and (count % increment) == 0:
+ print("Added contacts: %d" % count)
+
+ ldbs.sam.add(msg)
+ count += 1
+
+ ldbs.groupedCommit()
diff --git a/source4/scripting/devel/chgkrbtgtpass b/source4/scripting/devel/chgkrbtgtpass
new file mode 100644
index 0000000..2beb2e7
--- /dev/null
+++ b/source4/scripting/devel/chgkrbtgtpass
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) Matthieu Patou <mat@matws.net> 2010
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2015
+#
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+
+__docformat__ = "restructuredText"
+
+
+import optparse
+import sys
+# Allow to run from s4 source directory (without installing samba)
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+from samba.credentials import DONT_USE_KERBEROS
+from samba.auth import system_session
+from samba import param
+from samba.provision import find_provision_key_parameters
+from samba.upgradehelpers import (get_paths,
+ get_ldbs,
+ update_krbtgt_account_password)
+
+parser = optparse.OptionParser("chgkrbtgtpass [options]")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+
+opts = parser.parse_args()[0]
+
+lp = sambaopts.get_loadparm()
+smbconf = lp.configfile
+creds = credopts.get_credentials(lp)
+creds.set_kerberos_state(DONT_USE_KERBEROS)
+
+
+paths = get_paths(param, smbconf=smbconf)
+session = system_session()
+
+ldbs = get_ldbs(paths, creds, session, lp)
+ldbs.startTransactions()
+
+update_krbtgt_account_password(ldbs.sam)
+ldbs.groupedCommit()
diff --git a/source4/scripting/devel/chgtdcpass b/source4/scripting/devel/chgtdcpass
new file mode 100755
index 0000000..8f2415c
--- /dev/null
+++ b/source4/scripting/devel/chgtdcpass
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) Matthieu Patou <mat@matws.net> 2010
+#
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+
+__docformat__ = "restructuredText"
+
+
+import optparse
+import sys
+# Allow to run from s4 source directory (without installing samba)
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+from samba.credentials import DONT_USE_KERBEROS
+from samba.auth import system_session
+from samba import param
+from samba.provision import find_provision_key_parameters
+from samba.upgradehelpers import (get_paths,
+ get_ldbs,
+ update_machine_account_password)
+
+parser = optparse.OptionParser("chgtdcpass [options]")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+
+opts = parser.parse_args()[0]
+
+lp = sambaopts.get_loadparm()
+smbconf = lp.configfile
+creds = credopts.get_credentials(lp)
+creds.set_kerberos_state(DONT_USE_KERBEROS)
+
+
+if __name__ == '__main__':
+ paths = get_paths(param, smbconf=smbconf)
+ session = system_session()
+
+ ldbs = get_ldbs(paths, creds, session, lp)
+ ldbs.startTransactions()
+
+ names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap,
+ paths, smbconf, lp)
+
+ update_machine_account_password(ldbs.sam, ldbs.secrets, names)
+ ldbs.groupedCommit()
diff --git a/source4/scripting/devel/config_base b/source4/scripting/devel/config_base
new file mode 100755
index 0000000..f593f2f
--- /dev/null
+++ b/source4/scripting/devel/config_base
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+# this is useful for running samba tools with a different prefix
+
+# for example:
+# samba-tool $(scripting/devel/config_base /tmp/testprefix) join .....
+
+import sys, os
+
+vars = {
+ "ncalrpc dir" : "${PREFIX}/var/ncalrpc",
+ "private dir" : "${PREFIX}/private",
+ "lock dir" : "${PREFIX}/var/locks",
+ "pid directory" : "${PREFIX}/var/run",
+ "winbindd socket directory" : "${PREFIX}/var/run/winbindd",
+ "ntp signd socket directory" : "${PREFIX}/var/run/ntp_signd"
+}
+
+if len(sys.argv) != 2:
+ print("Usage: config_base BASEDIRECTORY")
+ sys.exit(1)
+
+prefix = sys.argv[1]
+
+config_dir = prefix + "/etc"
+config_file = config_dir + "/smb.conf"
+
+if not os.path.isdir(config_dir):
+ os.makedirs(config_dir, mode=0o755)
+if not os.path.isfile(config_file):
+ open(config_file, mode='w').close()
+
+options = (
+ " --configfile=${PREFIX}/etc/smb.conf"
+ "".join(" --option=%s=%s" % (v.replace(" ",""), vars[v]) for v in vars)
+ ).replace("${PREFIX}", prefix)
+
+
+print(options)
diff --git a/source4/scripting/devel/crackname b/source4/scripting/devel/crackname
new file mode 100755
index 0000000..021adfa
--- /dev/null
+++ b/source4/scripting/devel/crackname
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+
+# Copyright Matthieu Patou <mat@matws.net> 2011
+# script to call a DRSUAPI crackname
+# this is useful for plugfest testing and replication debug
+import sys
+from optparse import OptionParser
+
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+from samba.dcerpc import drsuapi, misc
+
+def do_DsBind(drs):
+ '''make a DsBind call, returning the binding handle'''
+ bind_info = drsuapi.DsBindInfoCtr()
+ bind_info.length = 28
+ bind_info.info = drsuapi.DsBindInfo28()
+ bind_info.info.supported_extensions = 0
+ (info, handle) = drs.DsBind(misc.GUID(drsuapi.DRSUAPI_DS_BIND_GUID), bind_info)
+ return handle
+
+
+########### main code ###########
+if __name__ == "__main__":
+ parser = OptionParser("crackname server [options]")
+ sambaopts = options.SambaOptions(parser)
+ parser.add_option_group(sambaopts)
+ credopts = options.CredentialsOptionsDouble(parser)
+ parser.add_option_group(credopts)
+
+ parser.add_option("", "--name", type='str',
+ default='{ED9F5546-9729-4B04-9385-3FCFE2B17BA1}', help="name to crack")
+ parser.add_option("", "--outformat", type='int',
+ default=drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ help='format desired')
+ parser.add_option("", "--informat", type='int',
+ default=drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+ help='format offered')
+
+ (opts, args) = parser.parse_args()
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if len(args) != 1:
+ parser.error("You must supply a server")
+
+ if creds.is_anonymous():
+ parser.error("You must supply credentials")
+
+ server = args[0]
+
+ binding_str = "ncacn_ip_tcp:%s[seal,print]" % server
+
+ drs = drsuapi.drsuapi(binding_str, lp, creds)
+ drs_handle = do_DsBind(drs)
+ print("DRS Handle: %s" % drs_handle)
+
+ req = drsuapi.DsNameRequest1()
+ names = drsuapi.DsNameString()
+ names.str = opts.name
+
+ req.codepage = 1252
+ req.language = 1033
+ req.format_flags = 0
+ req.format_offered = opts.informat
+ req.format_desired = opts.outformat
+ req.count = 1
+ req.names = [names]
+
+ (result, ctr) = drs.DsCrackNames(drs_handle, 1, req)
+ 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)
diff --git a/source4/scripting/devel/demodirsync.py b/source4/scripting/devel/demodirsync.py
new file mode 100755
index 0000000..e21dbbc
--- /dev/null
+++ b/source4/scripting/devel/demodirsync.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python
+
+import optparse
+import sys
+import base64
+
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+from samba.dcerpc import drsblobs, misc
+from samba.ndr import ndr_pack, ndr_unpack
+from samba import Ldb
+
+parser = optparse.OptionParser("demodirsync [options]")
+sambaopts = options.SambaOptions(parser)
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+
+parser.add_option("-b", type="string", metavar="BASE",
+ help="set base DN for the search")
+parser.add_option("--host", type="string", metavar="HOST",
+ help="Ip of the host")
+
+lp = sambaopts.get_loadparm()
+creds = credopts.get_credentials(lp)
+
+opts = parser.parse_args()[0]
+
+if opts.host is None:
+ print("Usage: demodirsync.py --host HOST [-b BASE]")
+ sys.exit(1)
+
+def printdirsync(ctl):
+ arr = ctl.split(':')
+ if arr[0] == 'dirsync':
+ print("Need to continue: %s" % arr[1])
+ cookie = ndr_unpack(drsblobs.ldapControlDirSyncCookie, base64.b64decode(arr[3]))
+ print("DC's NTDS guid: %s " % cookie.blob.guid1)
+ print("highest usn %s" % cookie.blob.highwatermark.highest_usn)
+ print("tmp higest usn %s" % cookie.blob.highwatermark.tmp_highest_usn)
+ print("reserved usn %s" % cookie.blob.highwatermark.reserved_usn)
+ if cookie.blob.extra_length > 0:
+ print("highest usn in extra %s" % cookie.blob.extra.ctr.cursors[0].highest_usn)
+ return cookie
+
+
+remote_ldb = Ldb("ldap://" + opts.host + ":389", credentials=creds, lp=lp)
+tab = []
+if opts.b:
+ base = opts.b
+else:
+ base = None
+
+guid = None
+(msgs, ctrls) = remote_ldb.search(expression="(samaccountname=administrator)", base=base, attrs=["objectClass"], controls=["dirsync:1:1:50"])
+if (len(ctrls)):
+ for ctl in ctrls:
+ arr = ctl.split(':')
+ if arr[0] == 'dirsync':
+ cookie = ndr_unpack(drsblobs.ldapControlDirSyncCookie, base64.b64decode(arr[3]))
+ guid = cookie.blob.guid1
+if not guid:
+ print("No dirsync control ... strange")
+ sys.exit(1)
+
+print("")
+print("Getting first guest without any cookie")
+(msgs, ctrls) = remote_ldb.searchex(expression="(samaccountname=guest)", base=base, attrs=["objectClass"], controls=["dirsync:1:1:50"])
+cookie = None
+if (len(ctrls)):
+ for ctl in ctrls:
+ cookie = printdirsync(ctl)
+ print("Returned %d entries" % len(msgs))
+
+savedcookie = cookie
+
+print("")
+print("Getting allusers with cookie")
+controls = ["dirsync:1:1:50:%s" % base64.b64encode(ndr_pack(cookie)).decode('utf8')]
+(msgs, ctrls) = remote_ldb.searchex(expression="(samaccountname=*)", base=base, attrs=["objectClass"], controls=controls)
+if (len(ctrls)):
+ for ctl in ctrls:
+ printdirsync(ctl)
+ print("Returned %d entries" % len(msgs))
+
+cookie = savedcookie
+cookie.blob.guid1 = misc.GUID("128a99bf-e2df-4832-ac0a-1fb625e530db")
+if cookie.blob.extra_length > 0:
+ cookie.blob.extra.ctr.cursors[0].source_dsa_invocation_id = misc.GUID("128a99bf-e2df-4832-ac0a-1fb625e530db")
+
+print("")
+print("Getting all the entries")
+controls = ["dirsync:1:1:50:%s" % base64.b64encode(ndr_pack(cookie)).decode('utf8')]
+(msgs, ctrls) = remote_ldb.searchex(expression="(objectclass=*)", base=base, controls=controls)
+cont = 0
+if (len(ctrls)):
+ for ctl in ctrls:
+ cookie = printdirsync(ctl)
+ if cookie is not None:
+ cont = (ctl.split(':'))[1]
+ print("Returned %d entries" % len(msgs))
+
+usn = cookie.blob.highwatermark.tmp_highest_usn
+if cookie.blob.extra_length > 0:
+ bigusn = cookie.blob.extra.ctr.cursors[0].highest_usn
+else:
+ bigusn = usn + 1000
+while (cont == "1"):
+ print("")
+ controls = ["dirsync:1:1:50:%s" % base64.b64encode(ndr_pack(cookie)).decode('utf8')]
+ (msgs, ctrls) = remote_ldb.searchex(expression="(objectclass=*)", base=base, controls=controls)
+ if (len(ctrls)):
+ for ctl in ctrls:
+ cookie = printdirsync(ctl)
+ if cookie is not None:
+ cont = (ctl.split(':'))[1]
+ print("Returned %d entries" % len(msgs))
+
+print("")
+print("Getting with cookie but usn changed to %d we should use the one in extra" % (bigusn - 1))
+cookie.blob.highwatermark.highest_usn = 0
+cookie.blob.highwatermark.tmp_highest_usn = usn - 2
+if cookie.blob.extra_length > 0:
+ print("here")
+ cookie.blob.extra.ctr.cursors[0].highest_usn = bigusn - 1
+controls = ["dirsync:1:1:50:%s" % base64.b64encode(ndr_pack(cookie)).decode('utf8')]
+(msgs, ctrls) = remote_ldb.searchex(expression="(objectclass=*)", base=base, controls=controls)
+if (len(ctrls)):
+ for ctl in ctrls:
+ cookie = printdirsync(ctl)
+ print("Returned %d entries" % len(msgs))
+
+print("")
+print("Getting with cookie but usn %d changed and extra/cursor GUID too" % (usn - 2))
+print(" so that it's (tmp)highest_usn that drives the limit")
+cookie.blob.highwatermark.highest_usn = 0
+cookie.blob.highwatermark.tmp_highest_usn = usn - 2
+if cookie.blob.extra_length > 0:
+ cookie.blob.extra.ctr.cursors[0].source_dsa_invocation_id = misc.GUID("128a99bf-e2df-4832-ac0a-1fb625e530db")
+ cookie.blob.extra.ctr.cursors[0].highest_usn = bigusn - 1
+controls = ["dirsync:1:1:50:%s" % base64.b64encode(ndr_pack(cookie)).decode('utf8')]
+(msgs, ctrls) = remote_ldb.searchex(expression="(objectclass=*)", base=base, controls=controls)
+if (len(ctrls)):
+ for ctl in ctrls:
+ cookie = printdirsync(ctl)
+ print("Returned %d entries" % len(msgs))
+
+print("")
+print("Getting with cookie but usn changed to %d" % (usn - 2))
+cookie.blob.highwatermark.highest_usn = 0
+cookie.blob.highwatermark.tmp_highest_usn = (usn - 2)
+if cookie.blob.extra_length > 0:
+ cookie.blob.extra.ctr.cursors[0].highest_usn = (usn - 2)
+controls = ["dirsync:1:1:50:%s" % base64.b64encode(ndr_pack(cookie)).decode('utf8')]
+(msgs, ctrls) = remote_ldb.searchex(expression="(objectclass=*)", base=base, controls=controls)
+if (len(ctrls)):
+ for ctl in ctrls:
+ cookie = printdirsync(ctl)
+ print("Returned %d entries" % len(msgs))
diff --git a/source4/scripting/devel/drs/fsmo.ldif.template b/source4/scripting/devel/drs/fsmo.ldif.template
new file mode 100644
index 0000000..d5b373a
--- /dev/null
+++ b/source4/scripting/devel/drs/fsmo.ldif.template
@@ -0,0 +1,75 @@
+dn: CN=RID Manager$,CN=System,BASEDN
+changetype: modify
+replace: fSMORoleOwner
+fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,C
+ N=Sites,CN=Configuration,BASEDN
+-
+
+dn: BASEDN
+changetype: modify
+replace: fSMORoleOwner
+fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,C
+ N=Sites,CN=Configuration,BASEDN
+-
+
+dn: CN=Infrastructure,BASEDN
+changetype: modify
+replace: fSMORoleOwner
+fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,C
+ N=Sites,CN=Configuration,BASEDN
+-
+
+dn: CN=Partitions,CN=Configuration,BASEDN
+changetype: modify
+replace: fSMORoleOwner
+fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN
+-
+
+dn: CN=Schema,CN=Configuration,BASEDN
+changetype: modify
+replace: fSMORoleOwner
+fSMORoleOwner: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN
+-
+
+dn: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN
+changetype: modify
+replace: options
+options: 1
+-
+
+dn: CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN
+changetype: modify
+replace: dNSHostName
+dNSHostName: MACHINE.DNSDOMAIN
+-
+
+dn: CN=NTDS Site Settings,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN
+changetype: modify
+replace: interSiteTopologyGenerator
+interSiteTopologyGenerator: CN=NTDS Settings,CN=MACHINE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,BASEDN
+-
+
+dn: CN=MACHINE,OU=Domain Controllers,BASEDN
+changetype: modify
+replace: servicePrincipalName
+servicePrincipalName: GC/MACHINE.DNSDOMAIN/DNSDOMAIN
+servicePrincipalName: HOST/MACHINE/NETBIOSDOMAIN
+servicePrincipalName: ldap/MACHINE/NETBIOSDOMAIN
+servicePrincipalName: ldap/MACHINE.DNSDOMAIN/ForestDnsZones.DNSDOMAIN
+servicePrincipalName: ldap/MACHINE.DNSDOMAIN/DomainDnsZones.DNSDOMAIN
+servicePrincipalName: DNS/MACHINE.DNSDOMAIN
+servicePrincipalName: RestrictedKrbHost/MACHINE.DNSDOMAIN
+servicePrincipalName: RestrictedKrbHost/MACHINE
+servicePrincipalName: HOST/MACHINE.DNSDOMAIN/NETBIOSDOMAIN
+servicePrincipalName: HOST/MACHINE
+servicePrincipalName: HOST/MACHINE.DNSDOMAIN
+servicePrincipalName: HOST/MACHINE.DNSDOMAIN/DNSDOMAIN
+servicePrincipalName: ldap/MACHINE.DNSDOMAIN/NETBIOSDOMAIN
+servicePrincipalName: ldap/MACHINE
+servicePrincipalName: ldap/MACHINE.DNSDOMAIN
+servicePrincipalName: ldap/MACHINE.DNSDOMAIN/DNSDOMAIN
+servicePrincipalName: E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
+servicePrincipalName: ldap/NTDSGUID._msdcs.DNSDOMAIN
+servicePrincipalName: Dfsr-12F9A27C-BF97-4787-9364-D31B6C55EB04/MACHINE.DNSDOMAIN
+servicePrincipalName: NtFrs-88f5d2bd-b646-11d2-a6d3-00c04fc9b232/MACHINE.DNSDOMAIN
+-
diff --git a/source4/scripting/devel/drs/named.conf.ad.template b/source4/scripting/devel/drs/named.conf.ad.template
new file mode 100644
index 0000000..071c98c
--- /dev/null
+++ b/source4/scripting/devel/drs/named.conf.ad.template
@@ -0,0 +1,6 @@
+zone "DNSDOMAIN" IN {
+ type forward;
+ forwarders {
+ SERVERIP;
+ };
+};
diff --git a/source4/scripting/devel/drs/revampire_ad.sh b/source4/scripting/devel/drs/revampire_ad.sh
new file mode 100755
index 0000000..cd3164c
--- /dev/null
+++ b/source4/scripting/devel/drs/revampire_ad.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -x
+
+. $(dirname $0)/vars
+
+$(dirname $0)/vampire_ad.sh || exit 1
+
+ntds_guid=$(sudo bin/ldbsearch -H $PREFIX/private/sam.ldb -b "CN=NTDS Settings,CN=$machine,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,$dn" objectGUID | grep ^objectGUID | awk '{print $2}')
+
+cp $PREFIX/private/$DNSDOMAIN.zone{.template,}
+sed -i "s/NTDSGUID/$ntds_guid/g" $PREFIX/private/$DNSDOMAIN.zone
+cp $PREFIX/private/named.conf{.local,}
+sudo rndc reconfig
+fsmotmp=$(mktemp fsmo.ldif.XXXXXXXXX)
+cp $(dirname $0)/fsmo.ldif.template $fsmotmp
+sed -i "s/NTDSGUID/$ntds_guid/g" $fsmotmp
+sed -i "s/MACHINE/$machine/g" $fsmotmp
+sed -i "s/DNSDOMAIN/$DNSDOMAIN/g" $fsmotmp
+sed -i "s/BASEDN/$dn/g" $fsmotmp
+sed -i "s/NETBIOSDOMAIN/$workgroup/g" $fsmotmp
+sudo bin/ldbmodify -H $PREFIX/private/sam.ldb $fsmotmp
+rm $fsmotmp
diff --git a/source4/scripting/devel/drs/unvampire_ad.sh b/source4/scripting/devel/drs/unvampire_ad.sh
new file mode 100755
index 0000000..c005374
--- /dev/null
+++ b/source4/scripting/devel/drs/unvampire_ad.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -x
+
+. $(dirname $0)/vars
+
+if [ -z "$site" ]; then
+ site="Default-First-Site-Name"
+fi
+
+bin/ldbdel -r -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=$machine,CN=Computers,$dn"
+bin/ldbdel -r -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=$machine,OU=Domain Controllers,$dn"
+bin/ldbdel -r -H ldap://$server.$DNSDOMAIN -U$workgroup/administrator%$pass "CN=$machine,CN=Servers,CN=$site,CN=Sites,CN=Configuration,$dn"
+rm -f $PREFIX/private/*.ldb
diff --git a/source4/scripting/devel/drs/vampire_ad.sh b/source4/scripting/devel/drs/vampire_ad.sh
new file mode 100755
index 0000000..f3cdc3c
--- /dev/null
+++ b/source4/scripting/devel/drs/vampire_ad.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -x
+
+. $(dirname $0)/vars
+
+namedtmp=$(mktemp named.conf.ad.XXXXXXXXX)
+cp $(dirname $0)/named.conf.ad.template $namedtmp
+sed -i "s/DNSDOMAIN/$DNSDOMAIN/g" $namedtmp
+sed -i "s/SERVERIP/$server_ip/g" $namedtmp
+chmod a+r $namedtmp
+mv -f $namedtmp $PREFIX/private/named.conf
+sudo rndc reconfig
+$(dirname $0)/unvampire_ad.sh
+
+cat <<EOF >nsupdate.txt
+update delete $DNSDOMAIN A $machine_ip
+show
+send
+EOF
+echo "$pass" | kinit administrator
+nsupdate -g nsupdate.txt
+
+REALM="$(echo $DNSDOMAIN | tr '[a-z]' '[A-Z]')"
+
+sudo $GDB bin/samba-tool domain join $DNSDOMAIN DC -Uadministrator%$pass -s $PREFIX/etc/smb.conf --option=realm=$REALM --option="ads:dc function level=4" --option="ads:min function level=0" -d2 "$@" || exit 1
+# PRIVATEDIR=$PREFIX/private sudo -E scripting/bin/setup_dns.sh $machine $DNSDOMAIN $machine_ip || exit 1
+#sudo rndc flush
diff --git a/source4/scripting/devel/drs/vars b/source4/scripting/devel/drs/vars
new file mode 100644
index 0000000..b69b9f9
--- /dev/null
+++ b/source4/scripting/devel/drs/vars
@@ -0,0 +1,12 @@
+DNSDOMAIN=ad.samba.example.com
+PREFIX="/data/samba/samba4/prefix.ad"
+export PYTHONPATH=$PYTHONPATH:$PREFIX/lib/python2.6/site-packages
+pass="penguin"
+machine="ruth"
+machine_ip="192.168.122.1"
+workgroup=adruth
+dn="DC=ad,DC=samba,DC=example,DC=com"
+server=win2008-1
+server_ip=192.168.122.53
+site="Default-First-Site-Name"
+
diff --git a/source4/scripting/devel/enumprivs b/source4/scripting/devel/enumprivs
new file mode 100755
index 0000000..389f7d0
--- /dev/null
+++ b/source4/scripting/devel/enumprivs
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+
+# script to enumerate LSA privileges on a server
+
+import sys
+from optparse import OptionParser
+
+sys.path.insert(0, "bin/python")
+
+import samba
+import samba.getopt as options
+from samba.dcerpc import lsa, security
+
+def get_display_name(lsaconn, pol_handle, name):
+ '''get the display name for a privilege'''
+ string = lsa.String()
+ string.string = name
+
+ (disp_names, ret_lang) = lsaconn.LookupPrivDisplayName(pol_handle, string, 0x409, 0)
+ return disp_names.string
+
+
+
+
+########### main code ###########
+if __name__ == "__main__":
+ parser = OptionParser("enumprivs [options] server")
+ sambaopts = options.SambaOptions(parser)
+ credopts = options.CredentialsOptionsDouble(parser)
+ parser.add_option_group(credopts)
+
+ (opts, args) = parser.parse_args()
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if len(args) != 1:
+ parser.error("You must supply a server")
+
+ if not creds.authentication_requested():
+ parser.error("You must supply credentials")
+
+ server = args[0]
+
+ binding_str = "ncacn_np:%s[print]" % server
+
+ lsaconn = lsa.lsarpc(binding_str, lp, creds)
+
+ objectAttr = lsa.ObjectAttribute()
+ objectAttr.sec_qos = lsa.QosInfo()
+
+ pol_handle = lsaconn.OpenPolicy2(''.decode('utf-8'),
+ objectAttr, security.SEC_FLAG_MAXIMUM_ALLOWED)
+
+ (handle, privs) = lsaconn.EnumPrivs(pol_handle, 0, 100)
+ for p in privs.privs:
+ disp_name = get_display_name(lsaconn, pol_handle, p.name.string)
+ print("0x%08x %31s \"%s\"" % (p.luid.low, p.name.string, disp_name))
diff --git a/source4/scripting/devel/getncchanges b/source4/scripting/devel/getncchanges
new file mode 100755
index 0000000..a1a4d14
--- /dev/null
+++ b/source4/scripting/devel/getncchanges
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+
+# script to call a DRS GetNCChanges from the command line
+# this is useful for plugfest testing
+import sys
+from optparse import OptionParser
+
+sys.path.insert(0, "bin/python")
+
+import samba, ldb
+import samba.getopt as options
+from samba.dcerpc import drsuapi, misc
+from samba.samdb import SamDB
+from samba.auth import system_session
+from samba.ndr import ndr_unpack
+from samba.drs_utils import drs_get_rodc_partial_attribute_set, drs_DsBind
+
+
+########### main code ###########
+if __name__ == "__main__":
+ parser = OptionParser("getncchanges [options] server")
+ sambaopts = options.SambaOptions(parser)
+ parser.add_option_group(sambaopts)
+ credopts = options.CredentialsOptionsDouble(parser)
+ parser.add_option_group(credopts)
+
+ parser.add_option("", "--dn", dest="dn", help="DN to replicate",)
+ parser.add_option("", "--exop", dest="exop", help="extended operation",)
+ parser.add_option("", "--pas", dest="use_pas", action='store_true', default=False,
+ help="send partial attribute set (for RODC)")
+ parser.add_option("", "--nb-iter", type='int', help="Number of getncchange iterations")
+ parser.add_option("", "--dest-dsa", type='str', help="destination DSA GUID")
+ parser.add_option("", "--rodc", action='store_true', default=False,
+ help='use RODC replica flags')
+ parser.add_option("", "--partial-rw", action='store_true', default=False,
+ help='use RW partial replica flags, not be confused with --pas')
+ parser.add_option("", "--replica-flags", type='int',
+ default=drsuapi.DRSUAPI_DRS_INIT_SYNC |
+ drsuapi.DRSUAPI_DRS_PER_SYNC |
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC |
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED,
+ help='replica flags')
+
+ (opts, args) = parser.parse_args()
+ if opts.rodc:
+ opts.replica_flags = drsuapi.DRSUAPI_DRS_INIT_SYNC |\
+ drsuapi.DRSUAPI_DRS_PER_SYNC |\
+ drsuapi.DRSUAPI_DRS_GET_ANC |\
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED |\
+ drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |\
+ drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP
+
+ if opts.partial_rw:
+ opts.replica_flags = drsuapi.DRSUAPI_DRS_INIT_SYNC |\
+ drsuapi.DRSUAPI_DRS_PER_SYNC |\
+ drsuapi.DRSUAPI_DRS_GET_ANC |\
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if len(args) != 1:
+ parser.error("You must supply a server")
+
+ if creds.is_anonymous():
+ parser.error("You must supply credentials")
+
+ if opts.partial_rw and opts.rodc:
+ parser.error("Can't specify --partial-rw and --rodc")
+
+ server = args[0]
+
+ binding_str = "ncacn_ip_tcp:%s[seal,print]" % server
+
+ drs = drsuapi.drsuapi(binding_str, lp, creds)
+ drs_handle, supported_extensions = drs_DsBind(drs)
+ print("DRS Handle: %s" % drs_handle)
+
+ req8 = drsuapi.DsGetNCChangesRequest8()
+
+ samdb = SamDB(url="ldap://%s" % server,
+ session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ if opts.use_pas:
+ local_samdb = SamDB(url=None, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ if opts.dn is None:
+ opts.dn = str(samdb.get_default_basedn())
+
+ if opts.exop is None:
+ exop = drsuapi.DRSUAPI_EXOP_NONE
+ else:
+ exop = int(opts.exop)
+
+ dest_dsa = opts.dest_dsa
+ if not dest_dsa:
+ 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)
+ else:
+ # TODO fixme
+ pass
+ if not dest_dsa:
+ print("Unable to find the dest_dsa automatically please specify it")
+ import sys
+ sys.exit(1)
+
+ null_guid = misc.GUID()
+ req8.destination_dsa_guid = misc.GUID(dest_dsa)
+ req8.source_dsa_invocation_id = misc.GUID(samdb.get_invocation_id())
+ req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
+ req8.naming_context.dn = opts.dn.decode("utf-8")
+ req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
+ req8.highwatermark.tmp_highest_usn = 0
+ req8.highwatermark.reserved_usn = 0
+ req8.highwatermark.highest_usn = 0
+ req8.uptodateness_vector = None
+ req8.replica_flags = opts.replica_flags
+ req8.max_object_count = 402
+ req8.max_ndr_size = 402116
+ req8.extended_op = exop
+ req8.fsmo_info = 0
+ if opts.use_pas:
+ req8.partial_attribute_set = drs_get_rodc_partial_attribute_set(local_samdb)
+ else:
+ req8.partial_attribute_set = None
+ req8.partial_attribute_set_ex = None
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+
+ nb_iter = 0
+ while True:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ nb_iter += 1
+ if ctr.more_data == 0 or opts.nb_iter == nb_iter:
+ break
+ req8.highwatermark = ctr.new_highwatermark
diff --git a/source4/scripting/devel/nmfind b/source4/scripting/devel/nmfind
new file mode 100755
index 0000000..865c0d7
--- /dev/null
+++ b/source4/scripting/devel/nmfind
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# find object files containing a symbol
+# for example:
+# nmfind foo_function $(find bin/default -name '*.o')
+
+TARGET=$1
+shift
+for f in $*; do
+ if nm $f 2>&1 | grep $TARGET >/dev/null; then
+ echo [$f]
+ nm $f | grep $TARGET
+ echo
+ fi
+done
diff --git a/source4/scripting/devel/pfm_verify.py b/source4/scripting/devel/pfm_verify.py
new file mode 100755
index 0000000..f29c1e5
--- /dev/null
+++ b/source4/scripting/devel/pfm_verify.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# script to verify cached prefixMap on remote
+# server against the prefixMap stored in Schema NC
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+import os
+import sys
+from optparse import OptionParser
+
+sys.path.insert(0, "bin/python")
+
+import samba
+import samba.getopt as options
+from ldb import SCOPE_BASE, SCOPE_SUBTREE
+from samba.dcerpc import drsuapi, misc, drsblobs
+from samba.drs_utils import drs_DsBind
+from samba.samdb import SamDB
+from samba.auth import system_session
+from samba.ndr import ndr_pack, ndr_unpack
+
+
+def _samdb_fetch_pfm(samdb):
+ """Fetch prefixMap stored in SamDB using LDB connection"""
+ res = samdb.search(base=samdb.get_schema_basedn(), expression="", scope=SCOPE_BASE, attrs=["*"])
+ assert len(res) == 1
+ pfm = ndr_unpack(drsblobs.prefixMapBlob,
+ str(res[0]['prefixMap']))
+
+ pfm_schi = _samdb_fetch_schi(samdb)
+
+ return (pfm.ctr, pfm_schi)
+
+
+def _samdb_fetch_schi(samdb):
+ """Fetch schemaInfo stored in SamDB using LDB connection"""
+ res = samdb.search(base=samdb.get_schema_basedn(), expression="", scope=SCOPE_BASE, attrs=["*"])
+ assert len(res) == 1
+ if 'schemaInfo' in res[0]:
+ pfm_schi = ndr_unpack(drsblobs.schemaInfoBlob,
+ str(res[0]['schemaInfo']))
+ else:
+ pfm_schi = drsblobs.schemaInfoBlob()
+ pfm_schi.marker = 0xFF
+ return pfm_schi
+
+
+def _drs_fetch_pfm(server, samdb, creds, lp):
+ """Fetch prefixMap using DRS interface"""
+ binding_str = "ncacn_ip_tcp:%s[print,seal]" % server
+
+ drs = drsuapi.drsuapi(binding_str, lp, creds)
+ (drs_handle, supported_extensions) = drs_DsBind(drs)
+ print("DRS Handle: %s" % drs_handle)
+
+ req8 = drsuapi.DsGetNCChangesRequest8()
+
+ dest_dsa = misc.GUID("9c637462-5b8c-4467-aef2-bdb1f57bc4ef")
+ replica_flags = 0
+
+ req8.destination_dsa_guid = dest_dsa
+ req8.source_dsa_invocation_id = misc.GUID(samdb.get_invocation_id())
+ req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
+ req8.naming_context.dn = samdb.get_schema_basedn()
+ req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
+ req8.highwatermark.tmp_highest_usn = 0
+ req8.highwatermark.reserved_usn = 0
+ req8.highwatermark.highest_usn = 0
+ req8.uptodateness_vector = None
+ req8.replica_flags = replica_flags
+ req8.max_object_count = 0
+ req8.max_ndr_size = 402116
+ req8.extended_op = 0
+ req8.fsmo_info = 0
+ req8.partial_attribute_set = None
+ req8.partial_attribute_set_ex = None
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ pfm = ctr.mapping_ctr
+ # check for schemaInfo element
+ pfm_it = pfm.mappings[-1]
+ assert pfm_it.id_prefix == 0
+ assert pfm_it.oid.length == 21
+ s = "".join(chr(x) for x in pfm_it.oid.binary_oid)
+ pfm_schi = ndr_unpack(drsblobs.schemaInfoBlob, s)
+ assert pfm_schi.marker == 0xFF
+ # remove schemaInfo element
+ pfm.num_mappings -= 1
+ return (pfm, pfm_schi)
+
+
+def _pfm_verify(drs_pfm, ldb_pfm):
+ errors = []
+ if drs_pfm.num_mappings != ldb_pfm.num_mappings:
+ errors.append("Different count of prefixes: drs = %d, ldb = %d"
+ % (drs_pfm.num_mappings, ldb_pfm.num_mappings))
+ count = min(drs_pfm.num_mappings, ldb_pfm.num_mappings)
+ for i in range(0, count):
+ it_err = []
+ drs_it = drs_pfm.mappings[i]
+ ldb_it = ldb_pfm.mappings[i]
+ if drs_it.id_prefix != ldb_it.id_prefix:
+ it_err.append("id_prefix")
+ if drs_it.oid.length != ldb_it.oid.length:
+ it_err.append("oid.length")
+ if drs_it.oid.binary_oid != ldb_it.oid.binary_oid:
+ it_err.append("oid.binary_oid")
+ if len(it_err):
+ errors.append("[%2d] differences in (%s)" % (i, it_err))
+ return errors
+
+
+def _pfm_schi_verify(drs_schi, ldb_schi):
+ errors = []
+ print(drs_schi.revision)
+ print(drs_schi.invocation_id)
+ if drs_schi.marker != ldb_schi.marker:
+ errors.append("Different marker in schemaInfo: drs = %d, ldb = %d"
+ % (drs_schi.marker, ldb_schi.marker))
+ if drs_schi.revision != ldb_schi.revision:
+ errors.append("Different revision in schemaInfo: drs = %d, ldb = %d"
+ % (drs_schi.revision, ldb_schi.revision))
+ if drs_schi.invocation_id != ldb_schi.invocation_id:
+ errors.append("Different invocation_id in schemaInfo: drs = %s, ldb = %s"
+ % (drs_schi.invocation_id, ldb_schi.invocation_id))
+ return errors
+
+
+########### main code ###########
+if __name__ == "__main__":
+ # command line parsing
+ parser = OptionParser("pfm_verify.py [options] server")
+ sambaopts = options.SambaOptions(parser)
+ parser.add_option_group(sambaopts)
+ credopts = options.CredentialsOptionsDouble(parser)
+ parser.add_option_group(credopts)
+
+ (opts, args) = parser.parse_args()
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if len(args) != 1:
+ if "DC_SERVER" not in os.environ.keys():
+ parser.error("You must supply a server")
+ args.append(os.environ["DC_SERVER"])
+
+ if creds.is_anonymous():
+ parser.error("You must supply credentials")
+
+ server = args[0]
+
+ samdb = SamDB(url="ldap://%s" % server,
+ session_info=system_session(lp),
+ credentials=creds, lp=lp)
+
+ exit_code = 0
+ (drs_pfm, drs_schi) = _drs_fetch_pfm(server, samdb, creds, lp)
+ (ldb_pfm, ldb_schi) = _samdb_fetch_pfm(samdb)
+ # verify prefixMaps
+ errors = _pfm_verify(drs_pfm, ldb_pfm)
+ if len(errors):
+ print("prefixMap verification errors:")
+ print("%s" % errors)
+ exit_code = 1
+ # verify schemaInfos
+ errors = _pfm_schi_verify(drs_schi, ldb_schi)
+ if len(errors):
+ print("schemaInfo verification errors:")
+ print("%s" % errors)
+ exit_code = 2
+
+ if exit_code != 0:
+ sys.exit(exit_code)
diff --git a/source4/scripting/devel/rebuild_zone.sh b/source4/scripting/devel/rebuild_zone.sh
new file mode 100755
index 0000000..94d1f9e
--- /dev/null
+++ b/source4/scripting/devel/rebuild_zone.sh
@@ -0,0 +1,109 @@
+#!/bin/sh
+# rebuild a zone file, adding all DCs
+
+[ $# -eq 2 ] || {
+ echo "rebuild_zone.sh <sam.ldb> <zonefile>"
+ exit 1
+}
+
+LDB="$1"
+ZFILE="$2"
+
+dnshostname=$(bin/ldbsearch -H $LDB --scope=base -b '' dnsHostname | grep ^dns | cut -d' ' -f2)
+host=$(echo $dnshostname | cut -d. -f1)
+realm=$(echo $dnshostname | cut -d. -f2-)
+GUIDs=$(bin/ldbsearch -H $LDB objectclass=ntdsdsa objectguid --cross-ncs | grep ^objectGUID | cut -d' ' -f2)
+DOMAINGUID=$(bin/ldbsearch -H $LDB --scope=base objectguid | grep ^objectGUID | cut -d' ' -f2)
+
+dcname()
+{
+ GUID=$1
+ echo $(bin/ldbsearch -H $LDB objectguid=$GUID dn --cross-ncs | grep CN=NTDS.Settings | cut -d, -f2 | cut -d= -f2)
+}
+
+getip()
+{
+ NAME=$1
+ ret=$(nmblookup $NAME | egrep '^[0-9]' | head -1 | cut -d' ' -f1)
+ test -n "$ret" || {
+ echo "Unable to find IP for $NAME. Using XX.XX.XX.XX. Please edit" 1>&2
+ echo "XX.XX.XX.XX"
+ }
+ echo $ret
+}
+
+echo "Generating header for host $host in realm $realm"
+cat <<EOF >$ZFILE
+; -*- zone -*-
+; generated by rebuild_zone.sh
+\$ORIGIN $realm.
+\$TTL 1W
+@ IN SOA @ hostmaster (
+ $(date +%Y%m%d%H) ; serial
+ 2D ; refresh
+ 4H ; retry
+ 6W ; expiry
+ 1W ) ; minimum
+ IN NS $host
+
+EOF
+
+for GUID in $GUIDs; do
+ dc=$(dcname $GUID)
+ echo "Generating IP for DC $dc"
+ ip=$(getip $dc)
+ test -n "$ip" || exit 1
+ echo " IN A $ip" >>$ZFILE
+done
+
+echo "; IP Addresses" >>$ZFILE
+for GUID in $GUIDs; do
+ dc=$(dcname $GUID)
+ ip=$(getip $dc)
+ test -n "$ip" || exit 1
+ echo "$dc IN A $ip" >>$ZFILE
+done
+
+for GUID in $GUIDs; do
+ dc=$(dcname $GUID)
+ ip=$(getip $dc)
+ test -n "$ip" || exit 1
+ echo "Generating zone body for DC $dc with IP $ip"
+ cat <<EOF >>$ZFILE
+;
+; Entries for $dc
+gc._msdcs IN A $ip
+$GUID._msdcs IN CNAME $dc
+_gc._tcp IN SRV 0 100 3268 $dc
+_gc._tcp.Default-First-Site-Name._sites IN SRV 0 100 3268 $dc
+_ldap._tcp.gc._msdcs IN SRV 0 100 389 $dc
+_ldap._tcp.Default-First-Site-Name._sites.gc._msdcs IN SRV 0 100 389 $dc
+_ldap._tcp IN SRV 0 100 389 $dc
+_ldap._tcp.dc._msdcs IN SRV 0 100 389 $dc
+_ldap._tcp.pdc._msdcs IN SRV 0 100 389 $dc
+_ldap._tcp.$DOMAINGUID.domains._msdcs IN SRV 0 100 389 $dc
+_ldap._tcp.Default-First-Site-Name._sites IN SRV 0 100 389 $dc
+_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs IN SRV 0 100 389 $dc
+_kerberos._tcp IN SRV 0 100 88 $dc
+_kerberos._tcp.dc._msdcs IN SRV 0 100 88 $dc
+_kerberos._tcp.Default-First-Site-Name._sites IN SRV 0 100 88 $dc
+_kerberos._tcp.Default-First-Site-Name._sites.dc._msdcs IN SRV 0 100 88 $dc
+_kerberos._udp IN SRV 0 100 88 $dc
+_kerberos-master._tcp IN SRV 0 100 88 $dc
+_kerberos-master._udp IN SRV 0 100 88 $dc
+_kpasswd._tcp IN SRV 0 100 464 $dc
+_kpasswd._udp IN SRV 0 100 464 $dc
+EOF
+done
+
+cat <<EOF >>$ZFILE
+
+; kerberos hack
+_kerberos IN TXT $(echo $realm | tr [a-z] [A-Z])
+EOF
+
+echo "Rebuilt zone file $ZFILE OK"
+
+echo "Reloading bind config"
+PATH="/usr/sbin:$PATH" rndc reload
+exit 0
diff --git a/source4/scripting/devel/repl_cleartext_pwd.py b/source4/scripting/devel/repl_cleartext_pwd.py
new file mode 100755
index 0000000..6439291
--- /dev/null
+++ b/source4/scripting/devel/repl_cleartext_pwd.py
@@ -0,0 +1,412 @@
+#!/usr/bin/env python3
+#
+# Copyright Stefan Metzmacher 2011-2012
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+# This is useful to sync passwords from an AD domain.
+#
+# $
+# $ source4/scripting/devel/repl_cleartext_pwd.py \
+# -Uadministrator%A1b2C3d4 \
+# 172.31.9.219 DC=bla,DC=base /tmp/cookie cleartext_utf8 131085 displayName
+# # starting at usn[0]
+# dn: CN=Test User1,CN=Users,DC=bla,DC=base
+# cleartext_utf8: A1b2C3d4
+# displayName:: VABlAHMAdAAgAFUAcwBlAHIAMQA=
+#
+# # up to usn[16449]
+# $
+# $ source4/scripting/devel/repl_cleartext_pwd.py \
+# -Uadministrator%A1b2C3d4
+# 172.31.9.219 DC=bla,DC=base cookie_file cleartext_utf8 131085 displayName
+# # starting at usn[16449]
+# # up to usn[16449]
+# $
+#
+
+import sys
+
+# Find right direction when running from source tree
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+from optparse import OptionParser
+
+from samba.dcerpc import drsuapi, drsblobs, misc
+from samba.ndr import ndr_pack, ndr_unpack, ndr_print
+
+import binascii
+import hashlib
+import Crypto.Cipher.ARC4
+import struct
+import os
+
+from ldif import LDIFWriter
+
+
+class globals:
+ def __init__(self):
+ self.global_objs = {}
+ self.ldif = LDIFWriter(sys.stdout)
+
+ def add_attr(self, dn, attname, vals):
+ if dn not in self.global_objs:
+ self.global_objs[dn] = {}
+ self.global_objs[dn][attname] = vals
+
+ def print_all(self):
+ for dn, obj in self.global_objs.items():
+ self.ldif.unparse(dn, obj)
+ continue
+ self.global_objs = {}
+
+
+def attid_equal(a1, a2):
+ return (a1 & 0xffffffff) == (a2 & 0xffffffff)
+
+
+########### main code ###########
+if __name__ == "__main__":
+ parser = OptionParser("repl_cleartext_pwd.py [options] server dn cookie_file clear_utf8_name [attid attname attmode] [clear_utf16_name")
+ sambaopts = options.SambaOptions(parser)
+ credopts = options.CredentialsOptions(parser)
+ parser.add_option_group(credopts)
+
+ (opts, args) = parser.parse_args()
+
+ if len(args) == 4:
+ pass
+ elif len(args) == 7:
+ pass
+ elif len(args) >= 8:
+ pass
+ else:
+ parser.error("more arguments required - given=%d" % (len(args)))
+
+ server = args[0]
+ dn = args[1]
+ cookie_file = args[2]
+ if len(cookie_file) == 0:
+ cookie_file = None
+ clear_utf8_name = args[3]
+ if len(args) >= 7:
+ try:
+ attid = int(args[4], 16)
+ except Exception:
+ attid = int(args[4])
+ attname = args[5]
+ attmode = args[6]
+ if attmode not in ["raw", "utf8"]:
+ parser.error("attmode should be 'raw' or 'utf8'")
+ else:
+ attid = -1
+ attname = None
+ attmode = "raw"
+ if len(args) >= 8:
+ clear_utf16_name = args[7]
+ else:
+ clear_utf16_name = None
+
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ if not creds.authentication_requested():
+ parser.error("You must supply credentials")
+
+ gls = globals()
+ try:
+ f = open(cookie_file, 'r')
+ store_blob = f.read()
+ f.close()
+
+ store_hdr = store_blob[0:28]
+ (store_version,
+ store_dn_len, store_dn_ofs,
+ store_hwm_len, store_hwm_ofs,
+ store_utdv_len, store_utdv_ofs) = \
+ struct.unpack("<LLLLLLL", store_hdr)
+
+ store_dn = store_blob[store_dn_ofs:store_dn_ofs + store_dn_len]
+ store_hwm_blob = store_blob[store_hwm_ofs:store_hwm_ofs + store_hwm_len]
+ store_utdv_blob = store_blob[store_utdv_ofs:store_utdv_ofs + store_utdv_len]
+
+ store_hwm = ndr_unpack(drsuapi.DsReplicaHighWaterMark, store_hwm_blob)
+ store_utdv = ndr_unpack(drsblobs.replUpToDateVectorBlob, store_utdv_blob)
+
+ assert store_dn == dn
+ # print "%s" % ndr_print(store_hwm)
+ # print "%s" % ndr_print(store_utdv)
+ except Exception:
+ store_dn = dn
+ store_hwm = drsuapi.DsReplicaHighWaterMark()
+ store_hwm.tmp_highest_usn = 0
+ store_hwm.reserved_usn = 0
+ store_hwm.highest_usn = 0
+ store_utdv = None
+
+ binding_str = "ncacn_ip_tcp:%s[spnego,seal]" % server
+
+ drs_conn = drsuapi.drsuapi(binding_str, lp, creds)
+
+ bind_info = drsuapi.DsBindInfoCtr()
+ bind_info.length = 28
+ bind_info.info = drsuapi.DsBindInfo28()
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_BASE
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
+ bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
+ (info, drs_handle) = drs_conn.DsBind(misc.GUID(drsuapi.DRSUAPI_DS_BIND_GUID), bind_info)
+
+ null_guid = misc.GUID()
+
+ naming_context = drsuapi.DsReplicaObjectIdentifier()
+ naming_context.dn = dn
+ highwatermark = store_hwm
+ uptodateness_vector = None
+ if store_utdv is not None:
+ uptodateness_vector = drsuapi.DsReplicaCursorCtrEx()
+ if store_utdv.version == 1:
+ uptodateness_vector.cursors = store_utdv.cursors
+ elif store_utdv.version == 2:
+ cursors = []
+ for i in range(0, store_utdv.ctr.count):
+ cursor = drsuapi.DsReplicaCursor()
+ cursor.source_dsa_invocation_id = store_utdv.ctr.cursors[i].source_dsa_invocation_id
+ cursor.highest_usn = store_utdv.ctr.cursors[i].highest_usn
+ cursors.append(cursor)
+ uptodateness_vector.cursors = cursors
+
+ req8 = drsuapi.DsGetNCChangesRequest8()
+
+ req8.destination_dsa_guid = null_guid
+ req8.source_dsa_invocation_id = null_guid
+ req8.naming_context = naming_context
+ req8.highwatermark = highwatermark
+ req8.uptodateness_vector = uptodateness_vector
+ req8.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC |
+ drsuapi.DRSUAPI_DRS_PER_SYNC |
+ drsuapi.DRSUAPI_DRS_GET_ANC |
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED |
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+ req8.max_object_count = 402
+ req8.max_ndr_size = 402116
+ req8.extended_op = 0
+ req8.fsmo_info = 0
+ req8.partial_attribute_set = None
+ req8.partial_attribute_set_ex = None
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+
+ user_session_key = drs_conn.user_session_key
+
+ print("# starting at usn[%d]" % (highwatermark.highest_usn))
+
+ while True:
+ (level, ctr) = drs_conn.DsGetNCChanges(drs_handle, 8, req8)
+ if ctr.first_object is None and ctr.object_count != 0:
+ raise RuntimeError("DsGetNCChanges: NULL first_object with object_count=%u" % (ctr.object_count))
+
+ obj_item = ctr.first_object
+ while obj_item is not None:
+ obj = obj_item.object
+
+ if obj.identifier is None:
+ obj_item = obj_item.next_object
+ continue
+
+ # print '%s' % obj.identifier.dn
+
+ is_deleted = False
+ for i in range(0, obj.attribute_ctr.num_attributes):
+ attr = obj.attribute_ctr.attributes[i]
+ if attid_equal(attr.attid, drsuapi.DRSUAPI_ATTID_isDeleted):
+ is_deleted = True
+ if is_deleted:
+ obj_item = obj_item.next_object
+ continue
+
+ spl_crypt = None
+ attvals = None
+ for i in range(0, obj.attribute_ctr.num_attributes):
+ attr = obj.attribute_ctr.attributes[i]
+ if attid_equal(attr.attid, attid):
+ attvals = []
+ for j in range(0, attr.value_ctr.num_values):
+ assert attr.value_ctr.values[j].blob is not None
+ val_raw = attr.value_ctr.values[j].blob
+ val = None
+ if attmode == "utf8":
+ val_unicode = unicode(val_raw, 'utf-16-le')
+ val = val_unicode.encode('utf-8')
+ elif attmode == "raw":
+ val = val_raw
+ else:
+ assert False, "attmode[%s]" % attmode
+ attvals.append(val)
+ if not attid_equal(attr.attid, drsuapi.DRSUAPI_ATTID_supplementalCredentials):
+ continue
+ assert attr.value_ctr.num_values <= 1
+ if attr.value_ctr.num_values == 0:
+ break
+ assert attr.value_ctr.values[0].blob is not None
+ spl_crypt = attr.value_ctr.values[0].blob
+
+ if spl_crypt is None:
+ obj_item = obj_item.next_object
+ continue
+
+ assert len(spl_crypt) >= 20
+ confounder = spl_crypt[0:16]
+ enc_buffer = spl_crypt[16:]
+
+ m5 = hashlib.md5()
+ m5.update(user_session_key)
+ m5.update(confounder)
+ enc_key = m5.digest()
+
+ rc4 = Crypto.Cipher.ARC4.new(enc_key)
+ plain_buffer = rc4.decrypt(enc_buffer)
+
+ (crc32_v) = struct.unpack("<L", plain_buffer[0:4])
+ attr_val = plain_buffer[4:]
+ crc32_c = binascii.crc32(attr_val) & 0xffffffff
+ assert int(crc32_v[0]) == int(crc32_c), "CRC32 0x%08X != 0x%08X" % (crc32_v[0], crc32_c)
+
+ spl = ndr_unpack(drsblobs.supplementalCredentialsBlob, attr_val)
+
+ # print '%s' % ndr_print(spl)
+
+ cleartext_hex = None
+
+ for i in range(0, spl.sub.num_packages):
+ pkg = spl.sub.packages[i]
+ if pkg.name != "Primary:CLEARTEXT":
+ continue
+ cleartext_hex = pkg.data
+
+ if cleartext_hex is not None:
+ cleartext_utf16 = binascii.a2b_hex(cleartext_hex)
+ if clear_utf16_name is not None:
+ gls.add_attr(obj.identifier.dn, clear_utf16_name, [cleartext_utf16])
+ try:
+ cleartext_unicode = unicode(cleartext_utf16, 'utf-16-le')
+ cleartext_utf8 = cleartext_unicode.encode('utf-8')
+ gls.add_attr(obj.identifier.dn, clear_utf8_name, [cleartext_utf8])
+ except Exception:
+ pass
+
+ if attvals is not None:
+ gls.add_attr(obj.identifier.dn, attname, attvals)
+
+ krb5_old_hex = None
+
+ for i in range(0, spl.sub.num_packages):
+ pkg = spl.sub.packages[i]
+ if pkg.name != "Primary:Kerberos":
+ continue
+ krb5_old_hex = pkg.data
+
+ if krb5_old_hex is not None:
+ krb5_old_raw = binascii.a2b_hex(krb5_old_hex)
+ krb5_old = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb5_old_raw, allow_remaining=True)
+
+ # print '%s' % ndr_print(krb5_old)
+
+ krb5_new_hex = None
+
+ for i in range(0, spl.sub.num_packages):
+ pkg = spl.sub.packages[i]
+ if pkg.name != "Primary:Kerberos-Newer-Keys":
+ continue
+ krb5_new_hex = pkg.data
+
+ if krb5_new_hex is not None:
+ krb5_new_raw = binascii.a2b_hex(krb5_new_hex)
+ krb5_new = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb5_new_raw, allow_remaining=True)
+
+ # print '%s' % ndr_print(krb5_new)
+
+ obj_item = obj_item.next_object
+
+ gls.print_all()
+
+ if ctr.more_data == 0:
+ store_hwm = ctr.new_highwatermark
+
+ store_utdv = drsblobs.replUpToDateVectorBlob()
+ store_utdv.version = ctr.uptodateness_vector.version
+ store_utdv_ctr = store_utdv.ctr
+ store_utdv_ctr.count = ctr.uptodateness_vector.count
+ store_utdv_ctr.cursors = ctr.uptodateness_vector.cursors
+ store_utdv.ctr = store_utdv_ctr
+
+ # print "%s" % ndr_print(store_hwm)
+ # print "%s" % ndr_print(store_utdv)
+
+ store_hwm_blob = ndr_pack(store_hwm)
+ store_utdv_blob = ndr_pack(store_utdv)
+
+ #
+ # uint32_t version '1'
+ # uint32_t dn_str_len
+ # uint32_t dn_str_ofs
+ # uint32_t hwm_blob_len
+ # uint32_t hwm_blob_ofs
+ # uint32_t utdv_blob_len
+ # uint32_t utdv_blob_ofs
+ store_hdr_len = 7 * 4
+ dn_ofs = store_hdr_len
+ hwm_ofs = dn_ofs + len(dn)
+ utdv_ofs = hwm_ofs + len(store_hwm_blob)
+ store_blob = struct.pack("<LLLLLLL", 1,
+ len(dn), dn_ofs,
+ len(store_hwm_blob), hwm_ofs,
+ len(store_utdv_blob), utdv_ofs) + \
+ dn + store_hwm_blob + store_utdv_blob
+
+ tmp_file = "%s.tmp" % cookie_file
+ f = open(tmp_file, 'wb')
+ f.write(store_blob)
+ f.close()
+ os.rename(tmp_file, cookie_file)
+
+ print("# up to usn[%d]" % (ctr.new_highwatermark.highest_usn))
+ break
+ print("# up to tmp_usn[%d]" % (ctr.new_highwatermark.highest_usn))
+ req8.highwatermark = ctr.new_highwatermark
diff --git a/source4/scripting/devel/rodcdns b/source4/scripting/devel/rodcdns
new file mode 100755
index 0000000..6830580
--- /dev/null
+++ b/source4/scripting/devel/rodcdns
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+# script to call a netlogon RODC DNS update
+
+import sys
+from optparse import OptionParser
+
+sys.path.insert(0, "bin/python")
+
+import samba
+import samba.getopt as options
+from samba.dcerpc import netlogon, winbind
+
+########### main code ###########
+if __name__ == "__main__":
+ parser = OptionParser("rodcdns [options]")
+ sambaopts = options.SambaOptions(parser)
+
+ parser.add_option("", "--weight", dest="weight", help="record weight", default=0, type='int')
+ parser.add_option("", "--priority", dest="priority", help="record priority", default=100, type='int')
+ parser.add_option("", "--port", dest="port", help="port number", default=389, type='int')
+ parser.add_option("", "--type", dest="type", help="record type", default=netlogon.NlDnsLdapAtSite, type='int')
+ parser.add_option("", "--site", dest="site", help="site name", default="Default-First-Site-Name")
+
+ (opts, args) = parser.parse_args()
+
+ lp = sambaopts.get_loadparm()
+
+ w = winbind.winbind("irpc:winbind_server", lp)
+
+ dns_names = netlogon.NL_DNS_NAME_INFO_ARRAY()
+ dns_names.count = 1
+ name = netlogon.NL_DNS_NAME_INFO()
+ name.type = opts.type
+ name.priority = opts.priority
+ name.weight = opts.weight
+ name.port = opts.port
+ name.dns_register = True
+ dns_names.names = [ name ]
+ site_name = opts.site
+
+ ret_names = w.DsrUpdateReadOnlyServerDnsRecords(site_name, 600, dns_names)
+ print("Status: %u" % ret_names.names[0].status)
diff --git a/source4/scripting/devel/speedtest.py b/source4/scripting/devel/speedtest.py
new file mode 100755
index 0000000..8c044c4
--- /dev/null
+++ b/source4/scripting/devel/speedtest.py
@@ -0,0 +1,235 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# This speed test aims to show difference in execution time for bulk
+# creation of user objects. This will help us compare
+# Samba4 vs MS Active Directory performance.
+
+# Copyright (C) Zahari Zahariev <zahari.zahariev@postpath.com> 2010
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+import optparse
+import sys
+import time
+import base64
+from decimal import Decimal
+
+sys.path.insert(0, "bin/python")
+import samba
+from samba.tests.subunitrun import TestProgram, SubunitOptions
+
+import samba.getopt as options
+
+from ldb import SCOPE_BASE, SCOPE_SUBTREE
+from samba.ndr import ndr_unpack
+from samba.dcerpc import security
+
+from samba.auth import system_session
+from samba import gensec, sd_utils
+from samba.samdb import SamDB
+from samba.credentials import Credentials
+import samba.tests
+from samba.tests import delete_force
+
+parser = optparse.OptionParser("speedtest.py [options] <host>")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+
+# use command line creds if available
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+subunitopts = SubunitOptions(parser)
+parser.add_option_group(subunitopts)
+opts, args = parser.parse_args()
+
+if len(args) < 1:
+ parser.print_usage()
+ sys.exit(1)
+
+host = args[0]
+
+lp = sambaopts.get_loadparm()
+creds = credopts.get_credentials(lp)
+creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
+
+#
+# Tests start here
+#
+
+
+class SpeedTest(samba.tests.TestCase):
+
+ def find_domain_sid(self, ldb):
+ res = ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
+ return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
+
+ def setUp(self):
+ super(SpeedTest, self).setUp()
+ self.ldb_admin = ldb
+ self.base_dn = ldb.domain_dn()
+ self.domain_sid = security.dom_sid(ldb.get_domain_sid())
+ self.user_pass = "samba123@"
+ print("baseDN: %s" % self.base_dn)
+
+ def create_user(self, user_dn):
+ ldif = """
+dn: """ + user_dn + """
+sAMAccountName: """ + user_dn.split(",")[0][3:] + """
+objectClass: user
+unicodePwd:: """ + base64.b64encode(("\"%s\"" % self.user_pass).encode('utf-16-le')).decode('utf8') + """
+url: www.example.com
+"""
+ self.ldb_admin.add_ldif(ldif)
+
+ def create_group(self, group_dn, desc=None):
+ ldif = """
+dn: """ + group_dn + """
+objectClass: group
+sAMAccountName: """ + group_dn.split(",")[0][3:] + """
+groupType: 4
+url: www.example.com
+"""
+ self.ldb_admin.add_ldif(ldif)
+
+ def create_bundle(self, count):
+ for i in range(count):
+ self.create_user("cn=speedtestuser%d,cn=Users,%s" % (i + 1, self.base_dn))
+
+ def remove_bundle(self, count):
+ for i in range(count):
+ delete_force(self.ldb_admin, "cn=speedtestuser%d,cn=Users,%s" % (i + 1, self.base_dn))
+
+ def remove_test_users(self):
+ res = ldb.search(base="cn=Users,%s" % self.base_dn, expression="(objectClass=user)", scope=SCOPE_SUBTREE)
+ dn_list = [item.dn for item in res if "speedtestuser" in str(item.dn)]
+ for dn in dn_list:
+ delete_force(self.ldb_admin, dn)
+
+
+class SpeedTestAddDel(SpeedTest):
+
+ def setUp(self):
+ super(SpeedTestAddDel, self).setUp()
+
+ def run_bundle(self, num):
+ print("\n=== Test ADD/DEL %s user objects ===\n" % num)
+ avg_add = Decimal("0.0")
+ avg_del = Decimal("0.0")
+ for x in [1, 2, 3]:
+ start = time.time()
+ self.create_bundle(num)
+ res_add = Decimal(str(time.time() - start))
+ avg_add += res_add
+ print(" Attempt %s ADD: %.3fs" % (x, float(res_add)))
+ #
+ start = time.time()
+ self.remove_bundle(num)
+ res_del = Decimal(str(time.time() - start))
+ avg_del += res_del
+ print(" Attempt %s DEL: %.3fs" % (x, float(res_del)))
+ print("Average ADD: %.3fs" % float(Decimal(avg_add) / Decimal("3.0")))
+ print("Average DEL: %.3fs" % float(Decimal(avg_del) / Decimal("3.0")))
+ print("")
+
+ def test_00000(self):
+ """ Remove possibly undeleted test users from previous test
+ """
+ self.remove_test_users()
+
+ def test_00010(self):
+ self.run_bundle(10)
+
+ def test_00100(self):
+ self.run_bundle(100)
+
+ def test_01000(self):
+ self.run_bundle(1000)
+
+ def _test_10000(self):
+ """ This test should be enabled preferably against MS Active Directory.
+ It takes quite the time against Samba4 (1-2 days).
+ """
+ self.run_bundle(10000)
+
+
+class AclSearchSpeedTest(SpeedTest):
+
+ def setUp(self):
+ super(AclSearchSpeedTest, self).setUp()
+ self.ldb_admin.newuser("acltestuser", "samba123@")
+ self.sd_utils = sd_utils.SDUtils(self.ldb_admin)
+ self.ldb_user = self.get_ldb_connection("acltestuser", "samba123@")
+ self.user_sid = self.sd_utils.get_object_sid(self.get_user_dn("acltestuser"))
+
+ def tearDown(self):
+ super(AclSearchSpeedTest, self).tearDown()
+ delete_force(self.ldb_admin, self.get_user_dn("acltestuser"))
+
+ def run_search_bundle(self, num, _ldb):
+ print("\n=== Creating %s user objects ===\n" % num)
+ self.create_bundle(num)
+ mod = "(A;;LC;;;%s)(D;;RP;;;%s)" % (str(self.user_sid), str(self.user_sid))
+ for i in range(num):
+ self.sd_utils.dacl_add_ace("cn=speedtestuser%d,cn=Users,%s" %
+ (i + 1, self.base_dn), mod)
+ print("\n=== %s user objects created ===\n" % num)
+ print("\n=== Test search on %s user objects ===\n" % num)
+ avg_search = Decimal("0.0")
+ for x in [1, 2, 3]:
+ start = time.time()
+ res = _ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_SUBTREE)
+ res_search = Decimal(str(time.time() - start))
+ avg_search += res_search
+ print(" Attempt %s SEARCH: %.3fs" % (x, float(res_search)))
+ print("Average Search: %.3fs" % float(Decimal(avg_search) / Decimal("3.0")))
+ self.remove_bundle(num)
+
+ def get_user_dn(self, name):
+ return "CN=%s,CN=Users,%s" % (name, self.base_dn)
+
+ def get_ldb_connection(self, target_username, target_password):
+ creds_tmp = Credentials()
+ creds_tmp.set_username(target_username)
+ creds_tmp.set_password(target_password)
+ creds_tmp.set_domain(creds.get_domain())
+ creds_tmp.set_realm(creds.get_realm())
+ creds_tmp.set_workstation(creds.get_workstation())
+ creds_tmp.set_gensec_features(creds_tmp.get_gensec_features()
+ | gensec.FEATURE_SEAL)
+ ldb_target = SamDB(url=host, credentials=creds_tmp, lp=lp)
+ return ldb_target
+
+ def test_search_01000(self):
+ self.run_search_bundle(1000, self.ldb_admin)
+
+ def test_search2_01000(self):
+ # allow the user to see objects but not attributes, all attributes will be filtered out
+ mod = "(A;;LC;;;%s)(D;;RP;;;%s)" % (str(self.user_sid), str(self.user_sid))
+ self.sd_utils.dacl_add_ace("CN=Users,%s" % self.base_dn, mod)
+ self.run_search_bundle(1000, self.ldb_user)
+
+# Important unit running information
+
+
+if "://" not in host:
+ host = "ldap://%s" % host
+
+ldb_options = ["modules:paged_searches"]
+ldb = SamDB(host, credentials=creds, session_info=system_session(), lp=lp, options=ldb_options)
+
+TestProgram(module=__name__, opts=subunitopts)
diff --git a/source4/scripting/devel/tmpfs.sh b/source4/scripting/devel/tmpfs.sh
new file mode 100755
index 0000000..e4798ec
--- /dev/null
+++ b/source4/scripting/devel/tmpfs.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# This sets up bin/ and st/ as tmpfs filesystems, which saves a lot of
+# time waiting on the disk!
+
+sudo echo "About to (re)mount bin and st as tmpfs"
+rm -rf bin st
+sudo umount bin >/dev/null 2>&1
+sudo umount st >/dev/null 2>&1
+mkdir -p bin st || exit 1
+sudo mount -t tmpfs /dev/null bin || exit 1
+sudo chown $USER bin/. || exit 1
+echo "tmpfs setup for bin/"
+sudo mount -t tmpfs /dev/null st || exit 1
+sudo chown $USER st/. || exit 1
+echo "tmpfs setup for st/"
diff --git a/source4/scripting/devel/watch_servers.sh b/source4/scripting/devel/watch_servers.sh
new file mode 100644
index 0000000..88d66a2
--- /dev/null
+++ b/source4/scripting/devel/watch_servers.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+[ $# -ge 3 ] || {
+ echo "Usage: watch_servers.sh DB1 DB2 PASSWORD SEARCH <attrs>"
+ exit 1
+}
+
+host1="$1"
+host2="$2"
+password="$3"
+search="$4"
+shift 4
+
+watch -n1 "echo '$host1:'; bin/ldbsearch -S -H $host1 -Uadministrator%$password '$search' description $* | egrep -v '^ref|Ref|returned|entries|referrals' | uniq; echo; echo '$host2:'; bin/ldbsearch -S -H $host2 -Uadministrator%$password '$search' description $* | egrep -v '^ref|Ref|returned|entries|referrals' | uniq;"