diff options
Diffstat (limited to '')
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;" |