From da2e34a134545113c19056e4b20b457676ac0215 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sat, 30 Apr 2011 01:20:32 +0400 Subject: provision: reorganize attributes so that we don't attribute with DN syntax that depends on non present object Autobuild-User: Matthieu Patou Autobuild-Date: Sat Apr 30 14:51:16 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/provision/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index ff9b00122d..bdca992412 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -1166,6 +1166,11 @@ def setup_samdb(path, session_info, provision_backend, lp, names, "DESCRIPTOR": descr, }) + # Now register this container in the root of the forest + msg = ldb.Message(ldb.Dn(samdb, names.domaindn)) + msg["subRefs"] = ldb.MessageElement(names.configdn , ldb.FLAG_MOD_ADD, + "subRefs") + # The LDIF here was created when the Schema object was constructed logger.info("Setting up sam.ldb schema") samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"]) -- cgit From 7f36f3effa200709df021789786f6e7555aef33c Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 21 Mar 2011 18:03:50 +0300 Subject: s4-samba-tool: allow specification of targetdir when joining as (RO)DC Autobuild-User: Matthieu Patou Autobuild-Date: Thu May 5 02:04:13 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/netcmd/join.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/join.py b/source4/scripting/python/samba/netcmd/join.py index 507253ab81..70b750191a 100644 --- a/source4/scripting/python/samba/netcmd/join.py +++ b/source4/scripting/python/samba/netcmd/join.py @@ -22,7 +22,7 @@ import samba.getopt as options from samba.net import Net, LIBNET_JOIN_AUTOMATIC from samba.netcmd import Command, CommandError, Option -from samba.dcerpc.misc import SEC_CHAN_WKSTA, SEC_CHAN_BDC +from samba.dcerpc.misc import SEC_CHAN_WKSTA from samba.join import join_RODC, join_DC class cmd_join(Command): @@ -39,12 +39,13 @@ class cmd_join(Command): takes_options = [ Option("--server", help="DC to join", type=str), Option("--site", help="site to join", type=str), + Option("--targetdir", help="where to store provision", type=str), ] takes_args = ["domain", "role?"] def run(self, domain, role=None, sambaopts=None, credopts=None, - versionopts=None, server=None, site=None): + versionopts=None, server=None, site=None, targetdir=None): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) net = Net(creds, lp, server=credopts.ipaddress) @@ -61,11 +62,11 @@ class cmd_join(Command): secure_channel_type = SEC_CHAN_WKSTA elif role == "DC": join_DC(server=server, creds=creds, lp=lp, domain=domain, - site=site, netbios_name=netbios_name) + site=site, netbios_name=netbios_name, targetdir=targetdir) return elif role == "RODC": join_RODC(server=server, creds=creds, lp=lp, domain=domain, - site=site, netbios_name=netbios_name) + site=site, netbios_name=netbios_name, targetdir=targetdir) return else: raise CommandError("Invalid role %s (possible values: MEMBER, BDC, RODC)" % role) -- cgit From 22cb631b4fd0647b70fbaaafaffda8712a84a999 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 2 May 2011 15:57:19 +1000 Subject: s4-interfaces Rename interfaces code so not to conflict with source3/ The iface_count, iface_n_bcast, and load_interfaces functions conflicted with functions of the same name in source3, so the source4 functions were renamed. Hopefully we can actually wrap one around the other in future. Andrew Bartlett --- source4/scripting/python/pyglue.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c index f89785f971..03460db8ff 100644 --- a/source4/scripting/python/pyglue.c +++ b/source4/scripting/python/pyglue.c @@ -149,22 +149,22 @@ static PyObject *py_interface_ips(PyObject *self, PyObject *args) return NULL; } - load_interfaces(tmp_ctx, lpcfg_interfaces(lp_ctx), &ifaces); + load_interface_list(tmp_ctx, lpcfg_interfaces(lp_ctx), &ifaces); - count = iface_count(ifaces); + count = iface_list_count(ifaces); /* first count how many are not loopback addresses */ for (ifcount = i = 0; i Date: Sun, 8 May 2011 13:31:32 +0300 Subject: selftest: Polish selftest-vars.sh a little so it can be used again Autobuild-User: Kamen Mazdrashki Autobuild-Date: Sun May 8 22:50:01 CEST 2011 on sn-devel-104 --- source4/scripting/devel/selftest-vars.sh | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/devel/selftest-vars.sh b/source4/scripting/devel/selftest-vars.sh index bc73c05407..a8f323dbda 100644 --- a/source4/scripting/devel/selftest-vars.sh +++ b/source4/scripting/devel/selftest-vars.sh @@ -2,38 +2,42 @@ # outside the test environment export UID_WRAPPER=1 -export NSS_WRAPPER_PASSWD=st/dc/passwd -export NSS_WRAPPER_GROUP=st/dc/group +export NSS_WRAPPER_PASSWD=$PWD/st/dc/passwd +export NSS_WRAPPER_GROUP=$PWD/st/dc/group export CONFIGURATION="--configfile=$PWD/st/dc/etc/smb.conf" +export VAMPIRE_DC_SERVER=localvampiredc +export VAMPIRE_DC_SERVER_IP=127.0.0.22 +export VAMPIRE_DC_NETBIOSNAME=localvampiredc1 +export VAMPIRE_DC_NETBIOSALIAS=localvampiredc export MEMBER_SERVER=localmember3 -export MEMBER_SERVER_IP=127.0.0.3 +export MEMBER_SERVER_IP=127.0.0.23 export MEMBER_NETBIOSNAME=localmember3 export MEMBER_NETBIOSALIAS=localmember export RPC_PROXY_SERVER=localrpcproxy4 -export RPC_PROXY_SERVER_IP=127.0.0.4 +export RPC_PROXY_SERVER_IP=127.0.0.24 export RPC_PROXY_NETBIOSNAME=localrpcproxy4 export RPC_PROXY_NETBIOSALIAS=localrpcproxy export SELFTEST_MAXTIME=1200 export NETBIOSNAME=localdc1 export REALM=SAMBA.EXAMPLE.COM -export SOCKET_WRAPPER_DEFAULT_IFACE=1 +export SOCKET_WRAPPER_DEFAULT_IFACE=21 export SERVER=localdc1 export WINBINDD_SOCKET_DIR=$PWD/st/dc/winbindd_socket export SELFTEST_PREFIX=$PWD/st export DOMAIN=SAMBADOMAIN export BINDIR=./bin -export DC_SERVER_IP=127.0.0.1 +export DC_SERVER_IP=127.0.0.21 export SELFTEST_INTERFACES=127.0.0.6/8,127.0.0.7/8,127.0.0.8/8,127.0.0.9/8,127.0.0.10/8,127.0.0.11/8 export SOCKET_WRAPPER_DIR=$PWD/st/w export DC_USERNAME=Administrator export USERNAME=Administrator -export SERVER_IP=127.0.0.1 +export SERVER_IP=127.0.0.21 export KRB5_CONFIG=$PWD/st/dc/etc/krb5.conf export PREFIX_ABS=$PWD/st export SRCDIR_ABS=$PWD -export PREFIX=./st -export KRB5CCNAME=./st/krb5ticket -export SRCDIR=. +export PREFIX=$PWD/st +export KRB5CCNAME=$PWD/st/krb5ticket +export SRCDIR=$PWD/ export TLS_ENABLED=yes export DC_NETBIOSALIAS=localdc export DC_NETBIOSNAME=localdc1 -- cgit From c2ac7473f38a1e61499f6cf01ce9de19bcd3abc6 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Fri, 13 May 2011 16:04:07 +0400 Subject: s4-python: raise an error if unable to bind remote ldap while joining --- source4/scripting/python/samba/join.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/join.py b/source4/scripting/python/samba/join.py index c0aee71407..b586e2cd5b 100644 --- a/source4/scripting/python/samba/join.py +++ b/source4/scripting/python/samba/join.py @@ -36,6 +36,11 @@ import talloc # this makes debugging easier talloc.enable_null_tracking() +class DCJoinException(Exception): + + def __init__(self, msg): + super(DCJoinException, self).__init__("Can't join, error: %s" % msg) + class dc_join(object): '''perform a DC join''' @@ -62,6 +67,12 @@ class dc_join(object): session_info=system_session(), credentials=ctx.creds, lp=ctx.lp) + try: + ctx.samdb.search(scope=ldb.SCOPE_ONELEVEL, attrs=["dn"]) + except ldb.LdbError, (enum, estr): + raise DCJoinException(estr) + + ctx.myname = netbios_name ctx.samname = "%s$" % ctx.myname ctx.base_dn = str(ctx.samdb.get_default_basedn()) -- cgit From 2a5ff1513fe07894e0f9f8ee3ac6fd5ea87a4a6d Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 15 May 2011 16:02:54 +0400 Subject: s4-python: keep wheel_gid as an integer --- source4/scripting/python/samba/upgradehelpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 48f492a7dc..729231e763 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -342,7 +342,7 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp) (security.SID_BUILTIN_ADMINISTRATORS), attrs=["xidNumber"]) if len(res9) == 1: - names.wheel_gid = res9[0]["xidNumber"] + names.wheel_gid = int(str(res9[0]["xidNumber"])) else: raise ProvisioningError("Unable to find uid/gid for Domain Admins rid") return names -- cgit From d24a22fe9a414bf37859967848c45f2a7494193d Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 15 May 2011 16:06:18 +0400 Subject: s4-python: add an option for just fixing gpo folders --- source4/scripting/bin/upgradeprovision | 385 +++++++++++++++++---------------- 1 file changed, 196 insertions(+), 189 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 8c79917d5e..4e48a48b45 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -151,6 +151,8 @@ parser.add_option("--debugall", action="store_true", help="Print all available information (very verbose)") parser.add_option("--resetfileacl", action="store_true", help="Force a reset on filesystem acls in sysvol / netlogon share") +parser.add_option("--fixntacl", action="store_true", + help="Only fix NT ACLs in sysvol / netlogon share") parser.add_option("--full", action="store_true", help="Perform full upgrade of the samdb (schema, configuration, new objects, ...") @@ -1609,80 +1611,81 @@ if __name__ == '__main__': adm_session = admin_session(lp, str(names.domainsid)) # So we reget handle on objects # ldbs = get_ldbs(paths, creds, adm_session, lp) + if not opts.fixntacl: + if not sanitychecks(ldbs.sam, names): + message(SIMPLE, "Sanity checks for the upgrade have failed. " + "Check the messages and correct the errors " + "before rerunning upgradeprovision") + ldbs.groupedRollback() + sys.exit(1) - if not sanitychecks(ldbs.sam, names): - message(SIMPLE, "Sanity checks for the upgrade have failed. " - "Check the messages and correct the errors " - "before rerunning upgradeprovision") - sys.exit(1) - - # Let's see provision parameters - print_provision_key_parameters(names) - - # 5) With all this information let's create a fresh new provision used as - # reference - message(SIMPLE, "Creating a reference provision") - provisiondir = tempfile.mkdtemp(dir=paths.private_dir, - prefix="referenceprovision") - newprovision(names, creds, session, smbconf, provisiondir, - provision_logger) - - # TODO - # 6) and 7) - # We need to get a list of object which SD is directly computed from - # defaultSecurityDescriptor. - # This will allow us to know which object we can rebuild the SD in case - # of change of the parent's SD or of the defaultSD. - # Get file paths of this new provision - newpaths = get_paths(param, targetdir=provisiondir) - new_ldbs = get_ldbs(newpaths, creds, session, lp) - new_ldbs.startTransactions() - - # 8) Populate some associative array to ease the update process - # List of attribute which are link and backlink - populate_links(new_ldbs.sam, names.schemadn) - # List of attribute with ASN DN synthax) - populate_dnsyntax(new_ldbs.sam, names.schemadn) - # 9) - update_privilege(newpaths.private_dir, paths.private_dir) - # 10) - oem = getOEMInfo(ldbs.sam, str(names.rootdn)) - # Do some modification on sam.ldb - ldbs.groupedCommit() - new_ldbs.groupedCommit() - deltaattr = None -# 11) - if re.match(".*alpha((9)|(\d\d+)).*", str(oem)): - # 11) A - # Starting from alpha9 we can consider that the structure is quite ok - # and that we should do only dela - deltaattr = delta_update_basesamdb(newpaths.samdb, - paths.samdb, - creds, - session, - lp, - message) - else: - # 11) B - simple_update_basesamdb(newpaths, paths, names) - ldbs = get_ldbs(paths, creds, session, lp) - removeProvisionUSN(ldbs.sam) - - ldbs.startTransactions() - minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1 - new_ldbs.startTransactions() - - # 12) - schema = Schema(names.domainsid, schemadn=str(names.schemadn)) - # We create a closure that will be invoked just before schema reload - def schemareloadclosure(): - basesam = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp, - options=["modules:"]) - doit = False - if deltaattr is not None and len(deltaattr) > 1: - doit = True - if doit: - deltaattr.remove("dn") + # Let's see provision parameters + print_provision_key_parameters(names) + + # 5) With all this information let's create a fresh new provision used as + # reference + message(SIMPLE, "Creating a reference provision") + provisiondir = tempfile.mkdtemp(dir=paths.private_dir, + prefix="referenceprovision") + newprovision(names, creds, session, smbconf, provisiondir, + provision_logger) + + # TODO + # 6) and 7) + # We need to get a list of object which SD is directly computed from + # defaultSecurityDescriptor. + # This will allow us to know which object we can rebuild the SD in case + # of change of the parent's SD or of the defaultSD. + # Get file paths of this new provision + newpaths = get_paths(param, targetdir=provisiondir) + new_ldbs = get_ldbs(newpaths, creds, session, lp) + new_ldbs.startTransactions() + + # 8) Populate some associative array to ease the update process + # List of attribute which are link and backlink + populate_links(new_ldbs.sam, names.schemadn) + # List of attribute with ASN DN synthax) + populate_dnsyntax(new_ldbs.sam, names.schemadn) + # 9) + update_privilege(newpaths.private_dir, paths.private_dir) + # 10) + oem = getOEMInfo(ldbs.sam, str(names.rootdn)) + # Do some modification on sam.ldb + ldbs.groupedCommit() + new_ldbs.groupedCommit() + deltaattr = None + # 11) + if re.match(".*alpha((9)|(\d\d+)).*", str(oem)): + # 11) A + # Starting from alpha9 we can consider that the structure is quite ok + # and that we should do only dela + deltaattr = delta_update_basesamdb(newpaths.samdb, + paths.samdb, + creds, + session, + lp, + message) + else: + # 11) B + simple_update_basesamdb(newpaths, paths, names) + ldbs = get_ldbs(paths, creds, session, lp) + removeProvisionUSN(ldbs.sam) + + ldbs.startTransactions() + minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1 + new_ldbs.startTransactions() + + # 12) + schema = Schema(names.domainsid, schemadn=str(names.schemadn)) + # We create a closure that will be invoked just before schema reload + def schemareloadclosure(): + basesam = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp, + options=["modules:"]) + doit = False + if deltaattr is not None and len(deltaattr) > 1: + doit = True + if doit: + deltaattr.remove("dn") for att in deltaattr: if att.lower() == "dn": continue @@ -1691,112 +1694,112 @@ if __name__ == '__main__': doit = False elif deltaattr.get(att) is None: doit = False - if doit: - message(CHANGE, "Applying delta to @ATTRIBUTES") - deltaattr.dn = ldb.Dn(basesam, "@ATTRIBUTES") - basesam.modify(deltaattr) + if doit: + message(CHANGE, "Applying delta to @ATTRIBUTES") + deltaattr.dn = ldb.Dn(basesam, "@ATTRIBUTES") + basesam.modify(deltaattr) + else: + message(CHANGE, "Not applying delta to @ATTRIBUTES because " + "there is not only add") + # 13) + if opts.full: + if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs, + schema, schemareloadclosure): + message(SIMPLE, "Rolling back all changes. Check the cause" + " of the problem") + message(SIMPLE, "Your system is as it was before the upgrade") + ldbs.groupedRollback() + new_ldbs.groupedRollback() + shutil.rmtree(provisiondir) + sys.exit(1) else: - message(CHANGE, "Not applying delta to @ATTRIBUTES because " - "there is not only add") - # 13) - if opts.full: - if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs, - schema, schemareloadclosure): - message(SIMPLE, "Rolling back all changes. Check the cause" - " of the problem") - message(SIMPLE, "Your system is as it was before the upgrade") - ldbs.groupedRollback() - new_ldbs.groupedRollback() - shutil.rmtree(provisiondir) - sys.exit(1) - else: - # Try to reapply the change also when we do not change the sam - # as the delta_upgrade - schemareloadclosure() - sync_calculated_attributes(ldbs.sam, names) + # Try to reapply the change also when we do not change the sam + # as the delta_upgrade + schemareloadclosure() + sync_calculated_attributes(ldbs.sam, names) + res = ldbs.sam.search(expression="(samaccountname=dns)", + scope=SCOPE_SUBTREE, attrs=["dn"], + controls=["search_options:1:2"]) + if len(res) > 0: + message(SIMPLE, "You still have the old DNS object for managing " + "dynamic DNS, but you didn't supply --full so " + "a correct update can't be done") + ldbs.groupedRollback() + new_ldbs.groupedRollback() + shutil.rmtree(provisiondir) + sys.exit(1) + # 14) + update_secrets(new_ldbs.secrets, ldbs.secrets, message) + # 14bis) res = ldbs.sam.search(expression="(samaccountname=dns)", - scope=SCOPE_SUBTREE, attrs=["dn"], - controls=["search_options:1:2"]) - if len(res) > 0: - message(SIMPLE, "You still have the old DNS object for managing " - "dynamic DNS, but you didn't supply --full so " - "a correct update can't be done") - ldbs.groupedRollback() - new_ldbs.groupedRollback() - shutil.rmtree(provisiondir) - sys.exit(1) - # 14) - update_secrets(new_ldbs.secrets, ldbs.secrets, message) - # 14bis) - res = ldbs.sam.search(expression="(samaccountname=dns)", - scope=SCOPE_SUBTREE, attrs=["dn"], - controls=["search_options:1:2"]) - - if (len(res) == 1): - ldbs.sam.delete(res[0]["dn"]) - res2 = ldbs.secrets.search(expression="(samaccountname=dns)", - scope=SCOPE_SUBTREE, attrs=["dn"]) - update_dns_account_password(ldbs.sam, ldbs.secrets, names) - message(SIMPLE, "IMPORTANT!!! " - "If you were using Dynamic DNS before you need " - "to update your configuration, so that the " - "tkey-gssapi-credential has the following value: " - "DNS/%s.%s" % (names.netbiosname.lower(), - names.realm.lower())) - # 15) - message(SIMPLE, "Update machine account") - update_machine_account_password(ldbs.sam, ldbs.secrets, names) - - # 16) SD should be created with admin but as some previous acl were so wrong - # that admin can't modify them we have first to recreate them with the good - # form but with system account and then give the ownership to admin ... - if not re.match(r'.*alpha(9|\d\d+)', str(oem)): - message(SIMPLE, "Fixing old povision SD") - fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) - - # We calculate the max USN before recalculating the SD because we might - # touch object that have been modified after a provision and we do not - # want that the next upgradeprovision thinks that it has a green light - # to modify them - - # 17) - maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) - - # 18) We rebuild SD only if defaultSecurityDescriptor is modified - # But in fact we should do it also if one object has its SD modified as - # child might need rebuild - if defSDmodified: - message(SIMPLE, "Updating SD") - ldbs.sam.set_session_info(adm_session) - # Alpha10 was a bit broken still - if re.match(r'.*alpha(\d|10)', str(oem)): + scope=SCOPE_SUBTREE, attrs=["dn"], + controls=["search_options:1:2"]) + + if (len(res) == 1): + ldbs.sam.delete(res[0]["dn"]) + res2 = ldbs.secrets.search(expression="(samaccountname=dns)", + scope=SCOPE_SUBTREE, attrs=["dn"]) + update_dns_account_password(ldbs.sam, ldbs.secrets, names) + message(SIMPLE, "IMPORTANT!!! " + "If you were using Dynamic DNS before you need " + "to update your configuration, so that the " + "tkey-gssapi-credential has the following value: " + "DNS/%s.%s" % (names.netbiosname.lower(), + names.realm.lower())) + # 15) + message(SIMPLE, "Update machine account") + update_machine_account_password(ldbs.sam, ldbs.secrets, names) + + # 16) SD should be created with admin but as some previous acl were so wrong + # that admin can't modify them we have first to recreate them with the good + # form but with system account and then give the ownership to admin ... + if not re.match(r'.*alpha(9|\d\d+)', str(oem)): + message(SIMPLE, "Fixing old povision SD") fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) - - # 19) - # Now we are quite confident in the recalculate process of the SD, we make - # it optional. - # Also the check must be done in a clever way as for the moment we just - # compare SDDL - if opts.debugchangesd: - check_updated_sd(new_ldbs.sam, ldbs.sam, names) - - # 20) - updateOEMInfo(ldbs.sam, str(names.rootdn)) - # 21) - check_for_DNS(newpaths.private_dir, paths.private_dir) - # 22) - if lastProvisionUSNs is not None: - update_provision_usn(ldbs.sam, minUSN, maxUSN) - if opts.full and (names.policyid is None or names.policyid_dc is None): - update_policyids(names, ldbs.sam) - if opts.full or opts.resetfileacl: + rebuild_sd(ldbs.sam, names) + + # We calculate the max USN before recalculating the SD because we might + # touch object that have been modified after a provision and we do not + # want that the next upgradeprovision thinks that it has a green light + # to modify them + + # 17) + maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) + + # 18) We rebuild SD only if defaultSecurityDescriptor is modified + # But in fact we should do it also if one object has its SD modified as + # child might need rebuild + if defSDmodified: + message(SIMPLE, "Updating SD") + ldbs.sam.set_session_info(adm_session) + # Alpha10 was a bit broken still + if re.match(r'.*alpha(\d|10)', str(oem)): + fix_partition_sd(ldbs.sam, names) + rebuild_sd(ldbs.sam, names) + + # 19) + # Now we are quite confident in the recalculate process of the SD, we make + # it optional. + # Also the check must be done in a clever way as for the moment we just + # compare SDDL + if opts.debugchangesd: + check_updated_sd(new_ldbs.sam, ldbs.sam, names) + + # 20) + updateOEMInfo(ldbs.sam, str(names.rootdn)) + # 21) + check_for_DNS(newpaths.private_dir, paths.private_dir) + # 22) + if lastProvisionUSNs is not None: + update_provision_usn(ldbs.sam, minUSN, maxUSN) + if opts.full and (names.policyid is None or names.policyid_dc is None): + update_policyids(names, ldbs.sam) + if opts.full or opts.resetfileacl or opts.fixntacl: try: update_gpo(paths, ldbs.sam, names, lp, message, 1) except ProvisioningError, e: message(ERROR, "The policy for domain controller is missing. " - "You should restart upgradeprovision with --full") + "You should restart upgradeprovision with --full") except IOError, e: message(ERROR, "Setting ACL not supported on your filesystem") else: @@ -1804,25 +1807,29 @@ if __name__ == '__main__': update_gpo(paths, ldbs.sam, names, lp, message, 0) except ProvisioningError, e: message(ERROR, "The policy for domain controller is missing. " - "You should restart upgradeprovision with --full") - ldbs.groupedCommit() - new_ldbs.groupedCommit() - message(SIMPLE, "Upgrade finished!") - # remove reference provision now that everything is done ! - # So we have reindexed first if need when the merged schema was reloaded - # (as new attributes could have quick in) - # But the second part of the update (when we update existing objects - # can also have an influence on indexing as some attribute might have their - # searchflag modificated - message(SIMPLE, "Reopenning samdb to trigger reindexing if needed " - "after modification") - samdb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp) - message(SIMPLE, "Reindexing finished") - - shutil.rmtree(provisiondir) + "You should restart upgradeprovision with --full") + if not opts.fixntacl: + ldbs.groupedCommit() + new_ldbs.groupedCommit() + message(SIMPLE, "Upgrade finished!") + # remove reference provision now that everything is done ! + # So we have reindexed first if need when the merged schema was reloaded + # (as new attributes could have quick in) + # But the second part of the update (when we update existing objects + # can also have an influence on indexing as some attribute might have their + # searchflag modificated + message(SIMPLE, "Reopenning samdb to trigger reindexing if needed " + "after modification") + samdb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp) + message(SIMPLE, "Reindexing finished") + + shutil.rmtree(provisiondir) + else: + ldbs.groupedRollback() + message(SIMPLE, "ACLs fixed !") except StandardError, err: message(ERROR, "A problem occurred while trying to upgrade your " - "provision. A full backup is located at %s" % backupdir) + "provision. A full backup is located at %s" % backupdir) if opts.debugall or opts.debugchange: (typ, val, tb) = sys.exc_info() traceback.print_exception(typ, val, tb) -- cgit From c6cc22adc059aeb6de50305b8a40d513d8f05bbc Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 16 May 2011 22:55:29 +1000 Subject: s4-libnet: Remove libnet_Join and create libnet_Join_member libnet_Join conflicts with a function in the source3 netapi of the same name, and the ability to join as a DC via this particular method is unused. Andrew Bartlett --- source4/scripting/python/samba/netcmd/join.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/join.py b/source4/scripting/python/samba/netcmd/join.py index 70b750191a..820709c9e3 100644 --- a/source4/scripting/python/samba/netcmd/join.py +++ b/source4/scripting/python/samba/netcmd/join.py @@ -59,7 +59,13 @@ class cmd_join(Command): role = role.upper() if role is None or role == "MEMBER": - secure_channel_type = SEC_CHAN_WKSTA + (join_password, sid, domain_name) = net.join_member(domain, + netbios_name, + LIBNET_JOIN_AUTOMATIC) + + self.outf.write("Joined domain %s (%s)\n" % (domain_name, sid)) + return + elif role == "DC": join_DC(server=server, creds=creds, lp=lp, domain=domain, site=site, netbios_name=netbios_name, targetdir=targetdir) @@ -70,10 +76,3 @@ class cmd_join(Command): return else: raise CommandError("Invalid role %s (possible values: MEMBER, BDC, RODC)" % role) - - (join_password, sid, domain_name) = net.join(domain, - netbios_name, - secure_channel_type, - LIBNET_JOIN_AUTOMATIC) - - self.outf.write("Joined domain %s (%s)\n" % (domain_name, sid)) -- cgit From fa3e2fc8bb3e935c65b7043382cad1d649cb68a6 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 18 May 2011 12:06:25 +1000 Subject: selftest: Re-enable strings.py from source3/stf as a python subunit test --- source4/scripting/python/pyglue.c | 32 +++++++ source4/scripting/python/samba/__init__.py | 2 + source4/scripting/python/samba/tests/strings.py | 104 +++++++++++++++++++++ .../scripting/python/samba/tests/unicodenames.py | 31 ++++++ 4 files changed, 169 insertions(+) create mode 100644 source4/scripting/python/samba/tests/strings.py create mode 100644 source4/scripting/python/samba/tests/unicodenames.py (limited to 'source4/scripting') diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c index 03460db8ff..0f2048aa89 100644 --- a/source4/scripting/python/pyglue.c +++ b/source4/scripting/python/pyglue.c @@ -25,6 +25,10 @@ void init_glue(void); +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + static PyObject *py_generate_random_str(PyObject *self, PyObject *args) { int len; @@ -173,6 +177,30 @@ static PyObject *py_interface_ips(PyObject *self, PyObject *args) return pylist; } +static PyObject *py_strcasecmp_m(PyObject *self, PyObject *args) +{ + char *s1, *s2; + + if (!PyArg_ParseTuple(args, "ss", &s1, &s2)) + return NULL; + + return PyInt_FromLong(strcasecmp_m(s1, s2)); +} + +static PyObject *py_strstr_m(PyObject *self, PyObject *args) +{ + char *s1, *s2, *ret; + + if (!PyArg_ParseTuple(args, "ss", &s1, &s2)) + return NULL; + + ret = strstr_m(s1, s2); + if (!ret) { + Py_RETURN_NONE; + } + return PyString_FromString(ret); +} + static PyMethodDef py_misc_methods[] = { { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS, "generate_random_str(len) -> string\n" @@ -192,6 +220,10 @@ static PyMethodDef py_misc_methods[] = { "get debug level" }, { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS, "get interface IP address list"}, + { "strcasecmp_m", (PyCFunction)py_strcasecmp_m, METH_VARARGS, + "(for testing) compare two strings using Samba's strcasecmp_m()"}, + { "strstr_m", (PyCFunction)py_strstr_m, METH_VARARGS, + "(for testing) find one string in another with Samba's strstr_m()"}, { NULL } }; diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 2a54f47d2b..dac69e7f62 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -348,3 +348,5 @@ nttime2string = _glue.nttime2string nttime2unix = _glue.nttime2unix unix2nttime = _glue.unix2nttime generate_random_password = _glue.generate_random_password +strcasecmp_m = _glue.strcasecmp_m +strstr_m = _glue.strstr_m diff --git a/source4/scripting/python/samba/tests/strings.py b/source4/scripting/python/samba/tests/strings.py new file mode 100644 index 0000000000..5f3e5c5bb7 --- /dev/null +++ b/source4/scripting/python/samba/tests/strings.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python + +# subunit test cases for Samba string functions. + +# Copyright (C) 2003 by Martin Pool +# Copyright (C) 2011 Andrew Bartlett +# +# 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 . + +# XXX: All this code assumes that the Unix character set is UTF-8, +# which is the most common setting. I guess it would be better to +# force it to that value while running the tests. I'm not sure of the +# best way to do that yet. +# +# -- mbp + +import sys, re +from unicodenames import * + +import samba.tests +from samba import strcasecmp_m, strstr_m + +def signum(a): + if a < 0: + return -1 + elif a > 0: + return +1 + else: + return 0 + + +class strcasecmp_m_Tests(samba.tests.TestCase): + """String comparisons in simple ASCII and unicode""" + def test_strcasecmp_m(self): + # A, B, strcasecmp(A, B) + cases = [('hello', 'hello', 0), + ('hello', 'goodbye', +1), + ('goodbye', 'hello', -1), + ('hell', 'hello', -1), + ('', '', 0), + ('a', '', +1), + ('', 'a', -1), + ('a', 'A', 0), + ('aa', 'aA', 0), + ('Aa', 'aa', 0), + ('longstring ' * 100, 'longstring ' * 100, 0), + ('longstring ' * 100, 'longstring ' * 100 + 'a', -1), + ('longstring ' * 100 + 'a', 'longstring ' * 100, +1), + (KATAKANA_LETTER_A, KATAKANA_LETTER_A, 0), + (KATAKANA_LETTER_A, 'a', 1), + ] + for a, b, expect in cases: + self.assertEquals(signum(strcasecmp_m(a.encode('utf-8'), + b.encode('utf-8'))), + expect) + +class strstr_m_Tests(samba.tests.TestCase): + """strstr_m tests in simple ASCII and unicode strings""" + def test_strstr_m(self): + # A, B, strstr_m(A, B) + cases = [('hello', 'hello', 'hello'), + ('hello', 'goodbye', None), + ('goodbye', 'hello', None), + ('hell', 'hello', None), + ('hello', 'hell', 'hello'), + ('', '', ''), + ('a', '', 'a'), + ('', 'a', None), + ('a', 'A', None), + ('aa', 'aA', None), + ('Aa', 'aa', None), + ('%v foo', '%v', '%v foo'), + ('foo %v foo', '%v', '%v foo'), + ('foo %v', '%v', '%v'), + ('longstring ' * 100, 'longstring ' * 99, 'longstring ' * 100), + ('longstring ' * 99, 'longstring ' * 100, None), + ('longstring a' * 99, 'longstring ' * 100 + 'a', None), + ('longstring ' * 100 + 'a', 'longstring ' * 100, 'longstring ' * 100 + 'a'), + (KATAKANA_LETTER_A, KATAKANA_LETTER_A + 'bcd', None), + (KATAKANA_LETTER_A + 'bcde', KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcde'), + ('d'+KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcd'), + ('d'+KATAKANA_LETTER_A + 'bd', KATAKANA_LETTER_A + 'bcd', None), + + ('e'+KATAKANA_LETTER_A + 'bcdf', KATAKANA_LETTER_A + 'bcd', KATAKANA_LETTER_A + 'bcdf'), + (KATAKANA_LETTER_A, KATAKANA_LETTER_A + 'bcd', None), + (KATAKANA_LETTER_A*3, 'a', None), + ] + for a, b, expect in cases: + if expect is not None: + expect = expect.encode('utf-8') + self.assertEquals(strstr_m(a.encode('utf-8'), + b.encode('utf-8')), + expect) diff --git a/source4/scripting/python/samba/tests/unicodenames.py b/source4/scripting/python/samba/tests/unicodenames.py new file mode 100644 index 0000000000..fa5d0efc8c --- /dev/null +++ b/source4/scripting/python/samba/tests/unicodenames.py @@ -0,0 +1,31 @@ +#! /usr/bin/python + +# Copyright (C) 2003 by Martin Pool +# +# 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 . + + +""" +Defines symbolic names for a few UNICODE characters, to make test +source code more readable on machines that don't have all the +necessary fonts. + +You can do "import *" on this file safely. +""" + +LATIN_CAPITAL_LETTER_N_WITH_TILDE = u'\u004e' +LATIN_CAPITAL_LETTER_O_WITH_DIARESIS = u'\u00d6' +LATIN_SMALL_LETTER_O_WITH_DIARESIS = u'\u00f6' + +KATAKANA_LETTER_A = u'\u30a2' -- cgit From 6071ed67bf413b0f9245be9038e2e600d8ebb5aa Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Fri, 20 May 2011 19:43:19 +0400 Subject: s4-python: move function find_provision_key_parameters to provision namespace as it can be used not only for upgradeprovision --- source4/scripting/bin/upgradeprovision | 4 +- source4/scripting/devel/chgtdcpass | 3 +- .../scripting/python/samba/provision/__init__.py | 106 ++++++++++++++++++++ .../python/samba/tests/upgradeprovisionneeddc.py | 4 +- source4/scripting/python/samba/upgradehelpers.py | 108 --------------------- 5 files changed, 112 insertions(+), 113 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 4e48a48b45..e58a2647b6 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -44,7 +44,7 @@ from ldb import (SCOPE_SUBTREE, SCOPE_BASE, FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE, MessageElement, Message, Dn) from samba import param, dsdb, Ldb -from samba.provision import (get_domain_descriptor, +from samba.provision import (get_domain_descriptor, find_provision_key_parameters, get_config_descriptor, ProvisioningError, get_last_provision_usn, get_max_usn, update_provision_usn, setup_path) @@ -52,7 +52,7 @@ from samba.schema import get_linked_attributes, Schema, get_schema_descriptor from samba.dcerpc import security, drsblobs, xattr from samba.ndr import ndr_unpack from samba.upgradehelpers import (dn_sort, get_paths, newprovision, - find_provision_key_parameters, get_ldbs, + get_ldbs, usn_in_range, identic_rename, get_diff_sddls, update_secrets, CHANGE, ERROR, SIMPLE, CHANGEALL, GUESS, CHANGESD, PROVISION, diff --git a/source4/scripting/devel/chgtdcpass b/source4/scripting/devel/chgtdcpass index dc249834e0..4f5ea15a80 100755 --- a/source4/scripting/devel/chgtdcpass +++ b/source4/scripting/devel/chgtdcpass @@ -29,8 +29,9 @@ 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, - find_provision_key_parameters, get_ldbs, + get_ldbs, update_machine_account_password) parser = optparse.OptionParser("chgtdcpass [options]") diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index bdca992412..a12b9b90c1 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -38,11 +38,13 @@ import uuid import socket import urllib import shutil +import string import ldb from samba.auth import system_session, admin_session import samba +from samba.dsdb import DS_DOMAIN_FUNCTION_2000 from samba import ( Ldb, check_all_substituted, @@ -217,6 +219,110 @@ class ProvisionNames(object): self.sitename = None self.smbconf = None +def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp): + """Get key provision parameters (realm, domain, ...) from a given provision + + :param samdb: An LDB object connected to the sam.ldb file + :param secretsdb: An LDB object connected to the secrets.ldb file + :param idmapdb: An LDB object connected to the idmap.ldb file + :param paths: A list of path to provision object + :param smbconf: Path to the smb.conf file + :param lp: A LoadParm object + :return: A list of key provision parameters + """ + names = ProvisionNames() + names.adminpass = None + + # NT domain, kerberos realm, root dn, domain dn, domain dns name + names.domain = string.upper(lp.get("workgroup")) + names.realm = lp.get("realm") + basedn = "DC=" + names.realm.replace(".",",DC=") + names.dnsdomain = names.realm.lower() + names.realm = string.upper(names.realm) + # netbiosname + # Get the netbiosname first (could be obtained from smb.conf in theory) + res = secretsdb.search(expression="(flatname=%s)" % + names.domain,base="CN=Primary Domains", + scope=ldb.SCOPE_SUBTREE, attrs=["sAMAccountName"]) + names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","") + + names.smbconf = smbconf + + # That's a bit simplistic but it's ok as long as we have only 3 + # partitions + current = samdb.search(expression="(objectClass=*)", + base="", scope=ldb.SCOPE_BASE, + attrs=["defaultNamingContext", "schemaNamingContext", + "configurationNamingContext","rootDomainNamingContext"]) + + names.configdn = current[0]["configurationNamingContext"] + configdn = str(names.configdn) + names.schemadn = current[0]["schemaNamingContext"] + if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb, + current[0]["defaultNamingContext"][0]))): + raise ProvisioningError(("basedn in %s (%s) and from %s (%s)" + "is not the same ..." % (paths.samdb, + str(current[0]["defaultNamingContext"][0]), + paths.smbconf, basedn))) + + names.domaindn=current[0]["defaultNamingContext"] + names.rootdn=current[0]["rootDomainNamingContext"] + # default site name + res3 = samdb.search(expression="(objectClass=*)", + base="CN=Sites," + configdn, scope=ldb.SCOPE_ONELEVEL, attrs=["cn"]) + names.sitename = str(res3[0]["cn"]) + + # dns hostname and server dn + res4 = samdb.search(expression="(CN=%s)" % names.netbiosname, + base="OU=Domain Controllers,%s" % basedn, + scope=ldb.SCOPE_ONELEVEL, attrs=["dNSHostName"]) + names.hostname = str(res4[0]["dNSHostName"]).replace("." + names.dnsdomain,"") + + server_res = samdb.search(expression="serverReference=%s" % res4[0].dn, + attrs=[], base=configdn) + names.serverdn = server_res[0].dn + + # invocation id/objectguid + res5 = samdb.search(expression="(objectClass=*)", + base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE, + attrs=["invocationID", "objectGUID"]) + names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0])) + names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0])) + + # domain guid/sid + res6 = samdb.search(expression="(objectClass=*)", base=basedn, + scope=ldb.SCOPE_BASE, attrs=["objectGUID", + "objectSid","msDS-Behavior-Version" ]) + names.domainguid = str(ndr_unpack(misc.GUID, res6[0]["objectGUID"][0])) + names.domainsid = ndr_unpack( security.dom_sid, res6[0]["objectSid"][0]) + if res6[0].get("msDS-Behavior-Version") is None or \ + int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000: + names.domainlevel = DS_DOMAIN_FUNCTION_2000 + else: + names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0]) + + # policy guid + res7 = samdb.search(expression="(displayName=Default Domain Policy)", + base="CN=Policies,CN=System," + basedn, + scope=ldb.SCOPE_ONELEVEL, attrs=["cn","displayName"]) + names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","") + # dc policy guid + res8 = samdb.search(expression="(displayName=Default Domain Controllers" + " Policy)", + base="CN=Policies,CN=System," + basedn, + scope=ldb.SCOPE_ONELEVEL, attrs=["cn","displayName"]) + if len(res8) == 1: + names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","") + else: + names.policyid_dc = None + res9 = idmapdb.search(expression="(cn=%s)" % + (security.SID_BUILTIN_ADMINISTRATORS), + attrs=["xidNumber"]) + if len(res9) == 1: + names.wheel_gid = res9[0]["xidNumber"] + else: + raise ProvisioningError("Unable to find uid/gid for Domain Admins rid") + return names def update_provision_usn(samdb, low, high, replace=False): """Update the field provisionUSN in sam.ldb diff --git a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py index 3a9c78e0dc..596cff6d3a 100644 --- a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py +++ b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py @@ -26,9 +26,9 @@ import shutil from samba import param from samba.credentials import Credentials from samba.auth import system_session -from samba.provision import getpolicypath +from samba.provision import getpolicypath,find_provision_key_parameters from samba.upgradehelpers import (get_paths, get_ldbs, - find_provision_key_parameters, identic_rename, + identic_rename, updateOEMInfo, getOEMInfo, update_gpo, delta_update_basesamdb, update_dns_account_password, diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 729231e763..66782bb31b 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -24,13 +24,11 @@ """Helpers used for upgrading between different database formats.""" import os -import string import re import shutil import samba from samba import Ldb, version, ntacls -from samba.dsdb import DS_DOMAIN_FUNCTION_2000 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE import ldb from samba.provision import (ProvisionNames, provision_paths_from_lp, @@ -242,112 +240,6 @@ def update_policyids(names, samdb): names.policyid_dc = None -def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp): - """Get key provision parameters (realm, domain, ...) from a given provision - - :param samdb: An LDB object connected to the sam.ldb file - :param secretsdb: An LDB object connected to the secrets.ldb file - :param idmapdb: An LDB object connected to the idmap.ldb file - :param paths: A list of path to provision object - :param smbconf: Path to the smb.conf file - :param lp: A LoadParm object - :return: A list of key provision parameters - """ - names = ProvisionNames() - names.adminpass = None - - # NT domain, kerberos realm, root dn, domain dn, domain dns name - names.domain = string.upper(lp.get("workgroup")) - names.realm = lp.get("realm") - basedn = "DC=" + names.realm.replace(".",",DC=") - names.dnsdomain = names.realm.lower() - names.realm = string.upper(names.realm) - # netbiosname - # Get the netbiosname first (could be obtained from smb.conf in theory) - res = secretsdb.search(expression="(flatname=%s)" % - names.domain,base="CN=Primary Domains", - scope=SCOPE_SUBTREE, attrs=["sAMAccountName"]) - names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","") - - names.smbconf = smbconf - - # That's a bit simplistic but it's ok as long as we have only 3 - # partitions - current = samdb.search(expression="(objectClass=*)", - base="", scope=SCOPE_BASE, - attrs=["defaultNamingContext", "schemaNamingContext", - "configurationNamingContext","rootDomainNamingContext"]) - - names.configdn = current[0]["configurationNamingContext"] - configdn = str(names.configdn) - names.schemadn = current[0]["schemaNamingContext"] - if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb, - current[0]["defaultNamingContext"][0]))): - raise ProvisioningError(("basedn in %s (%s) and from %s (%s)" - "is not the same ..." % (paths.samdb, - str(current[0]["defaultNamingContext"][0]), - paths.smbconf, basedn))) - - names.domaindn=current[0]["defaultNamingContext"] - names.rootdn=current[0]["rootDomainNamingContext"] - # default site name - res3 = samdb.search(expression="(objectClass=*)", - base="CN=Sites," + configdn, scope=SCOPE_ONELEVEL, attrs=["cn"]) - names.sitename = str(res3[0]["cn"]) - - # dns hostname and server dn - res4 = samdb.search(expression="(CN=%s)" % names.netbiosname, - base="OU=Domain Controllers,%s" % basedn, - scope=SCOPE_ONELEVEL, attrs=["dNSHostName"]) - names.hostname = str(res4[0]["dNSHostName"]).replace("." + names.dnsdomain,"") - - server_res = samdb.search(expression="serverReference=%s" % res4[0].dn, - attrs=[], base=configdn) - names.serverdn = server_res[0].dn - - # invocation id/objectguid - res5 = samdb.search(expression="(objectClass=*)", - base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE, - attrs=["invocationID", "objectGUID"]) - names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0])) - names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0])) - - # domain guid/sid - res6 = samdb.search(expression="(objectClass=*)", base=basedn, - scope=SCOPE_BASE, attrs=["objectGUID", - "objectSid","msDS-Behavior-Version" ]) - names.domainguid = str(ndr_unpack(misc.GUID, res6[0]["objectGUID"][0])) - names.domainsid = ndr_unpack( security.dom_sid, res6[0]["objectSid"][0]) - if res6[0].get("msDS-Behavior-Version") is None or \ - int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000: - names.domainlevel = DS_DOMAIN_FUNCTION_2000 - else: - names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0]) - - # policy guid - res7 = samdb.search(expression="(displayName=Default Domain Policy)", - base="CN=Policies,CN=System," + basedn, - scope=SCOPE_ONELEVEL, attrs=["cn","displayName"]) - names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","") - # dc policy guid - res8 = samdb.search(expression="(displayName=Default Domain Controllers" - " Policy)", - base="CN=Policies,CN=System," + basedn, - scope=SCOPE_ONELEVEL, attrs=["cn","displayName"]) - if len(res8) == 1: - names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","") - else: - names.policyid_dc = None - res9 = idmapdb.search(expression="(cn=%s)" % - (security.SID_BUILTIN_ADMINISTRATORS), - attrs=["xidNumber"]) - if len(res9) == 1: - names.wheel_gid = int(str(res9[0]["xidNumber"])) - else: - raise ProvisioningError("Unable to find uid/gid for Domain Admins rid") - return names - - def newprovision(names, creds, session, smbconf, provdir, logger): """Create a new provision. -- cgit From 22a638b6165518eb9e640b1437b4552d685925dc Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sat, 23 Apr 2011 13:47:27 +0400 Subject: s4-python: Remove not used imports --- source4/scripting/python/samba/provision/__init__.py | 6 ++---- source4/scripting/python/samba/upgradehelpers.py | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index a12b9b90c1..8433f23121 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -48,15 +48,13 @@ from samba.dsdb import DS_DOMAIN_FUNCTION_2000 from samba import ( Ldb, check_all_substituted, - in_source_tree, - source_tree_topdir, read_and_sub_file, setup_file, substitute_var, valid_netbios_name, version, ) -from samba.dcerpc import security +from samba.dcerpc import security, misc from samba.dcerpc.misc import ( SEC_CHAN_BDC, SEC_CHAN_WKSTA, @@ -284,7 +282,7 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp) # invocation id/objectguid res5 = samdb.search(expression="(objectClass=*)", - base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE, + base="CN=NTDS Settings,%s" % str(names.serverdn), scope=ldb.SCOPE_BASE, attrs=["invocationID", "objectGUID"]) names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0])) names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0])) diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 66782bb31b..16e4ea006a 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -31,13 +31,12 @@ import samba from samba import Ldb, version, ntacls from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE import ldb -from samba.provision import (ProvisionNames, provision_paths_from_lp, +from samba.provision import (provision_paths_from_lp, getpolicypath, set_gpos_acl, create_gpo_struct, FILL_FULL, provision, ProvisioningError, setsysvolacl, secretsdb_self_join) -from samba.dcerpc import misc, security, xattr +from samba.dcerpc import xattr from samba.dcerpc.misc import SEC_CHAN_BDC -from samba.ndr import ndr_unpack from samba.samdb import SamDB # All the ldb related to registry are commented because the path for them is -- cgit From a0db60d3eabc309c3e65915b00e023acd9a13897 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 26 Apr 2011 00:04:32 +0400 Subject: Add a script for renaming a DC --- source4/scripting/bin/renamedc | 200 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100755 source4/scripting/bin/renamedc (limited to 'source4/scripting') diff --git a/source4/scripting/bin/renamedc b/source4/scripting/bin/renamedc new file mode 100755 index 0000000000..0915b15783 --- /dev/null +++ b/source4/scripting/bin/renamedc @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# vim: expandtab +# +# Copyright (C) Matthieu Patou 2011 +# +# 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 . + + +import optparse +import sys +# Allow to run from s4 source directory (without installing samba) +sys.path.insert(0, "bin/python") + +import ldb +import samba +import samba.getopt as options +import os + +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, secretsdb_self_join +from samba.upgradehelpers import get_ldbs, get_paths + + +__docformat__ = "restructuredText" + +parser = optparse.OptionParser("provision [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) +parser.add_option("--oldname", + help="Old DC name") +parser.add_option("--newname", + help="New DC name") + +opts = parser.parse_args()[0] + +if len(sys.argv) == 1: + opts.interactive = True +lp = sambaopts.get_loadparm() +smbconf = lp.configfile + +creds = credopts.get_credentials(lp) +creds.set_kerberos_state(DONT_USE_KERBEROS) + + +if __name__ == '__main__': + global defSDmodified + defSDmodified = False + # 1) First get files paths + paths = get_paths(param, smbconf=smbconf) + # Get ldbs with the system session, it is needed for searching + # provision parameters + session = system_session() + + ldbs = get_ldbs(paths, creds, session, lp) + ldbs.sam.transaction_start() + ldbs.secrets.transaction_start() + + if opts.oldname is None or opts.newname is None: + raise Exception("Option oldname or newname is missing") + res = ldbs.sam.search(expression="(&(name=%s)(serverReferenceBL=*))" % opts.oldname) + if res is None or len(res) != 1: + raise Exception("Wrong number of result returned, are you sure of the old name %s" % + opts.oldname) + + # Ok got it then check that the new name is not used as well + res2 = ldbs.sam.search(expression="(&(name=%s)(objectclass=computer))" % opts.newname) + if len(res2) != 0: + raise Exception("Seems that %s is a name that already exists, pick another one" % + opts.newname) + + names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, + paths, smbconf, lp) + + #First rename the entry + # provision put the name in upper case so let's do it too ! + newdn = str(res[0].dn).replace("CN=%s" % opts.oldname, "CN=%s" % opts.newname.upper()) + dnobj = ldb.Dn(ldbs.sam, newdn) + ldbs.sam.rename(res[0].dn, dnobj) + + # Then change password and samaccountname and dnshostname + msg = ldb.Message(dnobj) + machinepass = samba.generate_random_password(128, 255) + mputf16 = machinepass.encode('utf-16-le') + + account = "%s$" % opts.newname.upper() + msg["clearTextPassword"] = ldb.MessageElement(mputf16, + ldb.FLAG_MOD_REPLACE, + "clearTextPassword") + + msg["sAMAccountName"] = ldb.MessageElement(account, + ldb.FLAG_MOD_REPLACE, + "sAMAccountName") + + msg["dNSHostName"] = ldb.MessageElement("%s.%s" % (opts.newname, + names.dnsdomain), + ldb.FLAG_MOD_REPLACE, + "dNSHostName") + ldbs.sam.modify(msg) + + # Do a self join one more time to resync the secrets file + res = ldbs.sam.search(expression=("dn=%s" % newdn), + attrs=["msDs-keyVersionNumber", "serverReferenceBL"]) + assert(len(res) == 1) + kvno = int(str(res[0]["msDs-keyVersionNumber"])) + serverbldn = ldb.Dn(ldbs.sam, str(res[0]["serverReferenceBL"])) + + secrets_msg = ldbs.secrets.search(expression="sAMAccountName=%s$" % + opts.oldname.upper(), + attrs=["secureChannelType"]) + + secChanType = int(secrets_msg[0]["secureChannelType"][0]) + + secretsdb_self_join(ldbs.secrets, domain=names.domain, + realm=names.realm, + domainsid=names.domainsid, + dnsdomain=names.dnsdomain, + netbiosname=opts.newname.upper(), + machinepass=machinepass, + key_version_number=kvno, + secure_channel_type=secChanType) + + # Update RID set reference as there is no back link for the moment. + + res = ldbs.sam.search(expression="(objectClass=rIDSet)", base=newdn, attrs=[]) + assert(len(res) == 1) + newridset = str(res[0].dn) + msg = ldb.Message(dnobj) + + msg["rIDSetReferences"] = ldb.MessageElement(newridset, + ldb.FLAG_MOD_REPLACE, + "rIDSetReferences") + ldbs.sam.modify(msg) + + # Update the server's sites configuration + if False: + # Desactivated for the moment we have a couple of issues with site + # renaming first one is that it's currently forbidden + # second one is that a lot of links are not backlinked + # and so won't be updated when the DN change (ie. fmsowner ...) + serverbl = str(serverbldn) + dnparts = serverbl.split(",") + dnparts[0] = "CN=%s" % opts.newname.upper() + newserverref = ",".join(dnparts) + + newserverrefdn = ldb.Dn(ldbs.sam, newserverref) + + ldbs.sam.rename(serverbldn, newserverrefdn) + + msg = ldb.Message(newserverrefdn) + msg["dNSHostName"] = ldb.MessageElement("%s.%s" % (opts.newname, + names.dnsdomain), + ldb.FLAG_MOD_REPLACE, + "dNSHostName") + ldbs.sam.modify(msg) + + try: + ldbs.sam.transaction_prepare_commit() + ldbs.secrets.transaction_prepare_commit() + except Exception: + ldbs.sam.rollback() + ldbs.secrets.rollback() + sys.exit(1) + + try: + ldbs.sam.transaction_commit() + ldbs.secrets.transaction_commit() + except Exception: + ldbs.sam.rollback() + ldbs.secrets.rollback() + + # All good so far + #print lp.get("private dir") + cf = open(lp.configfile) + ncfname = "%s.new" % lp.configfile + newconf = open(ncfname, 'w') + for l in cf.readlines(): + if l.find("netbios name") > 0: + newconf.write("\tnetbios name = %s\n" % opts.newname.upper()) + else: + newconf.write(l) + newconf.close() + cf.close() + os.rename(ncfname, lp.configfile) + -- cgit From 850cca3996605a45d3f203318a90d3941934a792 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 7 Feb 2011 09:55:26 +0300 Subject: add a demo script for dirsync Signed-off-by: Andrew Tridgell Autobuild-User: Matthieu Patou Autobuild-Date: Sat May 21 15:40:26 CEST 2011 on sn-devel-104 --- source4/scripting/devel/demodirsync.py | 156 +++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100755 source4/scripting/devel/demodirsync.py (limited to 'source4/scripting') diff --git a/source4/scripting/devel/demodirsync.py b/source4/scripting/devel/demodirsync.py new file mode 100755 index 0000000000..41dac6ff51 --- /dev/null +++ b/source4/scripting/devel/demodirsync.py @@ -0,0 +1,156 @@ +#!/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("get-descriptor [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] + +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 + pass +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))] +(msgs, ctrls) = remote_ldb.searchex(expression="(samaccountname=*)", base=base, attrs=["objectClass"], controls=controls) +if (len(ctrls)): + for ctl in ctrls: + cookie = 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))] +(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 != 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))] + (msgs, ctrls) = remote_ldb.searchex(expression="(objectclass=*)", base=base, controls=controls) + if (len(ctrls)): + for ctl in ctrls: + cookie = printdirsync(ctl) + if cookie != 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))] +(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))] +(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))] +(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) -- cgit From 53b0c44d8c0f21682220a212baa4b8a2e0f3ceae Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 23 May 2011 15:27:50 +1000 Subject: s4-provision Use correct tkey-gssapi-credential We changed to ${DNSNAME} (the fully qualified domain name) a while back, and while it's usually functionally idential to the previous setting, this breaks down if there is more than one DNS server. Andrew Bartlett --- source4/scripting/python/samba/provision/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index 8433f23121..f987fb8ef3 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -1749,6 +1749,7 @@ def provision(logger, session_info, credentials, smbconf=None, create_named_txt(paths.namedtxt, realm=names.realm, dnsdomain=names.dnsdomain, + dnsname = "%s.%s" % (names.hostname, names.dnsdomain), private_dir=paths.private_dir, keytab_name=paths.dns_keytab) logger.info("See %s for an example configuration include file for BIND", paths.namedconf) @@ -1985,7 +1986,7 @@ def create_named_conf(paths, realm, dnsdomain, setup_file(setup_path("named.conf.update"), paths.namedconf_update) -def create_named_txt(path, realm, dnsdomain, private_dir, +def create_named_txt(path, realm, dnsdomain, dnsname, private_dir, keytab_name): """Write out a file containing zone statements suitable for inclusion in a named.conf file (including GSS-TSIG configuration). @@ -1998,6 +1999,7 @@ def create_named_txt(path, realm, dnsdomain, private_dir, """ setup_file(setup_path("named.txt"), path, { "DNSDOMAIN": dnsdomain, + "DNSNAME" : dnsname, "REALM": realm, "DNS_KEYTAB": keytab_name, "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name), -- cgit From 726ee12bb450821f929e05ca1c708f3e33f909cf Mon Sep 17 00:00:00 2001 From: Theresa Halloran Date: Thu, 19 May 2011 16:17:07 -0400 Subject: s4/samba-tool: Move samba-tool enableaccount to samba-tool user enable command. Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/netcmd/__init__.py | 3 +- .../scripting/python/samba/netcmd/enableaccount.py | 60 ---------------------- source4/scripting/python/samba/netcmd/user.py | 42 +++++++++++++++ 3 files changed, 43 insertions(+), 62 deletions(-) delete mode 100644 source4/scripting/python/samba/netcmd/enableaccount.py (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index cf514d5c49..ee2e700a24 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -2,6 +2,7 @@ # Unix SMB/CIFS implementation. # Copyright (C) Jelmer Vernooij 2009 +# Copyright (C) Theresa Halloran 2011 # # 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 @@ -181,8 +182,6 @@ from samba.netcmd.setpassword import cmd_setpassword commands["setpassword"] = cmd_setpassword() from samba.netcmd.setexpiry import cmd_setexpiry commands["setexpiry"] = cmd_setexpiry() -from samba.netcmd.enableaccount import cmd_enableaccount -commands["enableaccount"] = cmd_enableaccount() from samba.netcmd.newuser import cmd_newuser commands["newuser"] = cmd_newuser() from samba.netcmd.netacl import cmd_acl diff --git a/source4/scripting/python/samba/netcmd/enableaccount.py b/source4/scripting/python/samba/netcmd/enableaccount.py deleted file mode 100644 index 3ceddb3fd9..0000000000 --- a/source4/scripting/python/samba/netcmd/enableaccount.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# -# Enables an user account on a Samba4 server -# Copyright Jelmer Vernooij 2008 -# -# Based on the original in EJS: -# Copyright Andrew Tridgell 2005 -# -# 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 . -# - -import samba.getopt as options - -from samba.auth import system_session -from samba.netcmd import Command, CommandError, Option -from samba.samdb import SamDB - -class cmd_enableaccount(Command): - """Enables a user""" - - synopsis = "enableaccount [username] [options]" - - takes_optiongroups = { - "sambaopts": options.SambaOptions, - "versionopts": options.VersionOptions, - "credopts": options.CredentialsOptions, - } - - takes_options = [ - Option("-H", help="LDB URL for database or target server", type=str), - Option("--filter", help="LDAP Filter to set password on", type=str), - ] - - takes_args = ["username?"] - - def run(self, username=None, sambaopts=None, credopts=None, - versionopts=None, filter=None, H=None): - if username is None and filter is None: - raise CommandError("Either the username or '--filter' must be specified!") - - if filter is None: - filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) - - lp = sambaopts.get_loadparm() - creds = credopts.get_credentials(lp, fallback_machine=True) - - samdb = SamDB(url=H, session_info=system_session(), - credentials=creds, lp=lp) - samdb.enable_account(filter) diff --git a/source4/scripting/python/samba/netcmd/user.py b/source4/scripting/python/samba/netcmd/user.py index a5750b5010..5f53263523 100644 --- a/source4/scripting/python/samba/netcmd/user.py +++ b/source4/scripting/python/samba/netcmd/user.py @@ -3,6 +3,7 @@ # user management # # Copyright Jelmer Vernooij 2010 +# Copyright Theresa Halloran 2011 # # 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 @@ -19,6 +20,10 @@ # import samba.getopt as options +import sys +from samba.auth import system_session +from samba.samdb import SamDB + from samba.net import Net @@ -26,6 +31,7 @@ from samba.netcmd import ( Command, CommandError, SuperCommand, + Option, ) class cmd_user_add(Command): @@ -70,6 +76,41 @@ class cmd_user_delete(Command): except RuntimeError, msg: raise CommandError("Failed to delete user %s: %s" % (name, msg)) +class cmd_user_enable(Command): + """Enables a user""" + + synopsis = "%prog user enable [options]" + + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--filter", help="LDAP Filter to set password on", type=str), + ] + + takes_args = ["username?"] + + def run(self, username=None, sambaopts=None, credopts=None, + versionopts=None, filter=None, H=None): + if username is None and filter is None: + raise CommandError("Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp, fallback_machine=True) + + samdb = SamDB(url=H, session_info=system_session(), + credentials=creds, lp=lp) + samdb.enable_account(filter) + + class cmd_user(SuperCommand): """User management [server connection needed]""" @@ -77,4 +118,5 @@ class cmd_user(SuperCommand): subcommands = {} subcommands["add"] = cmd_user_add() subcommands["delete"] = cmd_user_delete() + subcommands["enable"] = cmd_user_enable() -- cgit From 23177b5f44815bc5b46943c70d37dc626ed60288 Mon Sep 17 00:00:00 2001 From: Theresa Halloran Date: Thu, 19 May 2011 16:24:00 -0400 Subject: s4:samba-tool: Move samba-tool setexpiry to samba-tool user setexpiry Signed-off-by: Andrew Tridgell --- source4/scripting/python/samba/netcmd/__init__.py | 2 - source4/scripting/python/samba/netcmd/setexpiry.py | 67 ---------------------- source4/scripting/python/samba/netcmd/user.py | 38 +++++++++++- 3 files changed, 37 insertions(+), 70 deletions(-) delete mode 100644 source4/scripting/python/samba/netcmd/setexpiry.py (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index ee2e700a24..d934cf8af6 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -180,8 +180,6 @@ from samba.netcmd.domainlevel import cmd_domainlevel commands["domainlevel"] = cmd_domainlevel() from samba.netcmd.setpassword import cmd_setpassword commands["setpassword"] = cmd_setpassword() -from samba.netcmd.setexpiry import cmd_setexpiry -commands["setexpiry"] = cmd_setexpiry() from samba.netcmd.newuser import cmd_newuser commands["newuser"] = cmd_newuser() from samba.netcmd.netacl import cmd_acl diff --git a/source4/scripting/python/samba/netcmd/setexpiry.py b/source4/scripting/python/samba/netcmd/setexpiry.py deleted file mode 100644 index bd8ea166fa..0000000000 --- a/source4/scripting/python/samba/netcmd/setexpiry.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -# -# Sets the user password expiry on a Samba4 server -# Copyright Jelmer Vernooij 2008 -# -# Based on the original in EJS: -# Copyright Andrew Tridgell 2005 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from samba.netcmd import Command, CommandError, Option - -import samba.getopt as options - -from samba.auth import system_session -from samba.samdb import SamDB - -class cmd_setexpiry(Command): - """Sets the expiration of a user account""" - - synopsis = "setexpiry [username] [options]" - - takes_optiongroups = { - "sambaopts": options.SambaOptions, - "versionopts": options.VersionOptions, - "credopts": options.CredentialsOptions, - } - - takes_options = [ - Option("-H", help="LDB URL for database or target server", type=str), - Option("--filter", help="LDAP Filter to set password on", type=str), - Option("--days", help="Days to expiry", type=int), - Option("--noexpiry", help="Password does never expire", action="store_true"), - ] - - takes_args = ["username?"] - - def run(self, username=None, sambaopts=None, credopts=None, - versionopts=None, H=None, filter=None, days=None, noexpiry=None): - if username is None and filter is None: - raise CommandError("Either the username or '--filter' must be specified!") - - if filter is None: - filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) - - lp = sambaopts.get_loadparm() - creds = credopts.get_credentials(lp) - - if days is None: - days = 0 - - samdb = SamDB(url=H, session_info=system_session(), - credentials=creds, lp=lp) - - samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry) diff --git a/source4/scripting/python/samba/netcmd/user.py b/source4/scripting/python/samba/netcmd/user.py index 5f53263523..696c8892cf 100644 --- a/source4/scripting/python/samba/netcmd/user.py +++ b/source4/scripting/python/samba/netcmd/user.py @@ -110,7 +110,43 @@ class cmd_user_enable(Command): credentials=creds, lp=lp) samdb.enable_account(filter) +class cmd_user_setexpiry(Command): + """Sets the expiration of a user account""" + synopsis = "%prog user setexpiry [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option("-H", help="LDB URL for database or target server", type=str), + Option("--filter", help="LDAP Filter to set password on", type=str), + Option("--days", help="Days to expiry", type=int), + Option("--noexpiry", help="Password does never expire", action="store_true"), + ] + + takes_args = ["username?"] + def run(self, username=None, sambaopts=None, credopts=None, + versionopts=None, H=None, filter=None, days=None, noexpiry=None): + if username is None and filter is None: + raise CommandError("Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if days is None: + days = 0 + + samdb = SamDB(url=H, session_info=system_session(), + credentials=creds, lp=lp) + + samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry) class cmd_user(SuperCommand): """User management [server connection needed]""" @@ -119,4 +155,4 @@ class cmd_user(SuperCommand): subcommands["add"] = cmd_user_add() subcommands["delete"] = cmd_user_delete() subcommands["enable"] = cmd_user_enable() - + subcommands["setexpiry"] = cmd_user_setexpiry() -- cgit From 7b3d8b6c908a37bb06e413dee406cebd29b99b3e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 1 Jun 2011 14:41:51 +1000 Subject: samba-tool: improved user enable error handling --- source4/scripting/python/samba/netcmd/user.py | 7 ++++++- source4/scripting/python/samba/samdb.py | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/user.py b/source4/scripting/python/samba/netcmd/user.py index 696c8892cf..15be4bb87f 100644 --- a/source4/scripting/python/samba/netcmd/user.py +++ b/source4/scripting/python/samba/netcmd/user.py @@ -108,7 +108,12 @@ class cmd_user_enable(Command): samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp) - samdb.enable_account(filter) + try: + samdb.enable_account(filter) + except Exception, msg: + raise CommandError("Failed to enable user %s: %s" % (username or filter, msg)) + print("Enabled user %s" % (username or filter)) + class cmd_user_setexpiry(Command): """Sets the expiration of a user account""" diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 99f141e664..2cea198e6b 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -79,6 +79,8 @@ class SamDB(samba.Ldb): """ res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, expression=search_filter, attrs=["userAccountControl"]) + if len(res) == 0: + raise Exception('Unable to find user "%s"' % search_filter) assert(len(res) == 1) user_dn = res[0].dn -- cgit From 1bc1ac0d084976fccf187526f7bd8d9ad818da10 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 1 Jun 2011 14:46:04 +1000 Subject: samba-tool: improved error handling in user setexpiry --- source4/scripting/python/samba/netcmd/user.py | 6 +++++- source4/scripting/python/samba/samdb.py | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/user.py b/source4/scripting/python/samba/netcmd/user.py index 15be4bb87f..6acf52d790 100644 --- a/source4/scripting/python/samba/netcmd/user.py +++ b/source4/scripting/python/samba/netcmd/user.py @@ -151,7 +151,11 @@ class cmd_user_setexpiry(Command): samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp) - samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry) + try: + samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry) + except Exception, msg: + raise CommandError("Failed to set expiry for user %s: %s" % (username or filter, msg)) + print("Set expiry for user %s to %u days" % (username or filter, days)) class cmd_user(SuperCommand): """User management [server connection needed]""" diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 2cea198e6b..a5c627e5b5 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -108,6 +108,8 @@ userAccountControl: %u """ res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, expression=search_filter, attrs=[]) + if len(res) == 0: + raise Exception('Unable to find user "%s"' % search_filter) assert(len(res) == 1) user_dn = res[0].dn @@ -411,6 +413,8 @@ unicodePwd:: %s res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, expression=search_filter, attrs=["userAccountControl", "accountExpires"]) + if len(res) == 0: + raise Exception('Unable to find user "%s"' % search_filter) assert(len(res) == 1) user_dn = res[0].dn -- cgit From 2f67fae18be13f4bfce009e8639bab74383844cb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 2 Jun 2011 10:22:06 +0930 Subject: samba3sam.py: don't assume order of ldb results. Switching to tdb2 breaks this test horribly, because it relied on the order of TDB1 traversal. Fix it to sort te results (by db), then check them. Signed-off-by: Rusty Russell --- source4/scripting/python/samba/tests/samba3sam.py | 306 ++++++++++++---------- 1 file changed, 164 insertions(+), 142 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/tests/samba3sam.py b/source4/scripting/python/samba/tests/samba3sam.py index a34f0f620c..99b9c0655e 100644 --- a/source4/scripting/python/samba/tests/samba3sam.py +++ b/source4/scripting/python/samba/tests/samba3sam.py @@ -30,6 +30,7 @@ from samba.tests import TestCaseInTempDir, env_loadparm import samba.dcerpc.security import samba.ndr from samba.auth import system_session +from operator import attrgetter def read_datafile(filename): @@ -439,34 +440,37 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 res = self.ldb.search(expression="(revision=x)", scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[0]["dnsHostName"]), "x") + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[1]["dnsHostName"]), "y") + self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by kept attribute res = self.ldb.search(expression="(description=y)", scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[0]["dnsHostName"]), "z") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "z") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[1]) + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[1]["dnsHostName"]), "z") self.assertEquals(str(res[1]["lastLogon"]), "z") # Search by renamed attribute res = self.ldb.search(expression="(badPwdCount=x)", scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "x") + self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by converted attribute # TODO: @@ -475,18 +479,19 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 #res = self.ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", scope=SCOPE_DEFAULT, attrs) res = self.ldb.search(expression="(objectSid=*)", base=None, scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon", "objectSid"]) self.assertEquals(len(res), 4) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[0]["dnsHostName"]), "x") - self.assertEquals(str(res[0]["lastLogon"]), "x") - self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552", - res[0]["objectSid"]) - self.assertTrue("objectSid" in res[0]) - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) - self.assertTrue(not "dnsHostName" in res[1]) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552", res[1]["objectSid"]) self.assertTrue("objectSid" in res[1]) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) + self.assertTrue(not "dnsHostName" in res[0]) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552", + res[0]["objectSid"]) + self.assertTrue("objectSid" in res[0]) # Search by generated attribute # In most cases, this even works when the mapping is missing @@ -519,12 +524,13 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 attrs = ["dnsHostName", "lastLogon", "objectClass"] res = self.ldb.search(expression="(objectClass=user)", attrs=attrs) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[0]["dnsHostName"]), "x") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) + self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") self.assertEquals(str(res[0]["objectClass"][0]), "user") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) - self.assertTrue(not "dnsHostName" in res[1]) + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") self.assertEquals(str(res[1]["objectClass"][0]), "user") @@ -532,18 +538,19 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 res = self.ldb.search(expression="(|(objectClass=user)(badPwdCount=x))", attrs=attrs) self.assertEquals(len(res), 3) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(set(res[0]["objectClass"]), set(["top"])) - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[1]["objectClass"][0]), "user") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A")) - self.assertTrue(not "dnsHostName" in res[2]) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(res[0]["objectClass"][0], "user") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) + self.assertTrue(not "dnsHostName" in res[1]) + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(set(res[1]["objectClass"]), set(["top"])) + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[2]["dnsHostName"]), "x") self.assertEquals(str(res[2]["lastLogon"]), "x") - self.assertEquals(res[2]["objectClass"][0], "user") + self.assertEquals(str(res[2]["objectClass"][0]), "user") # Testing search by parse tree @@ -551,34 +558,37 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 res = self.ldb.search(expression="(&(codePage=x)(revision=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[0]["dnsHostName"]), "x") + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[1]["dnsHostName"]), "y") + self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by conjunction of remote attributes res = self.ldb.search(expression="(&(lastLogon=x)(description=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[0]["dnsHostName"]), "x") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) + self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) - self.assertTrue(not "dnsHostName" in res[1]) + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[1]["dnsHostName"]), "x") self.assertEquals(str(res[1]["lastLogon"]), "x") # Search by conjunction of local and remote attribute res = self.ldb.search(expression="(&(codePage=x)(description=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[0]["dnsHostName"]), "x") + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[1]["dnsHostName"]), "y") + self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by conjunction of local and remote attribute w/o match attrs = ["dnsHostName", "lastLogon"] @@ -593,40 +603,43 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 res = self.ldb.search(expression="(|(revision=x)(dnsHostName=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 2) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[0]["dnsHostName"]), "x") + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[1]["dnsHostName"]), "y") + self.assertEquals(str(res[1]["lastLogon"]), "y") # Search by disjunction of remote attributes res = self.ldb.search(expression="(|(badPwdCount=x)(lastLogon=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 3) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertFalse("dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A")) - self.assertFalse("dnsHostName" in res[2]) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) + self.assertFalse("dnsHostName" in res[1]) + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[2]["dnsHostName"]), "x") self.assertEquals(str(res[2]["lastLogon"]), "x") # Search by disjunction of local and remote attribute res = self.ldb.search(expression="(|(revision=x)(lastLogon=y))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 3) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + self.assertFalse("dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) - self.assertFalse("dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "y") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[2]["dnsHostName"]), "x") - self.assertEquals(str(res[2]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[1]["dnsHostName"]), "x") + self.assertEquals(str(res[1]["lastLogon"]), "x") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[2]["dnsHostName"]), "y") + self.assertEquals(str(res[2]["lastLogon"]), "y") # Search by disjunction of local and remote attribute w/o match res = self.ldb.search(expression="(|(codePage=y)(nextRid=z))", @@ -637,142 +650,151 @@ objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 res = self.ldb.search(expression="(!(revision=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[2]["dnsHostName"]), "z") + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") - self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[3]) + self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated remote attribute res = self.ldb.search(expression="(!(description=x))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 4) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[0]["dnsHostName"]), "z") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "z") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[1]) + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[1]["dnsHostName"]), "z") self.assertEquals(str(res[1]["lastLogon"]), "z") # Search by negated conjunction of local attributes res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[2]["dnsHostName"]), "z") + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") - self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[3]) + self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated conjunction of remote attributes res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "y") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[2]["dnsHostName"]), "z") - self.assertEquals(str(res[2]["lastLogon"]), "z") - self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[3]) + self.assertEquals(str(res[1]["lastLogon"]), "z") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[2]["dnsHostName"]), "y") + self.assertEquals(str(res[2]["lastLogon"]), "y") + self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated conjunction of local and remote attribute res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 6) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[2]["dnsHostName"]), "z") + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") - self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[3]) + self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated disjunction of local attributes res = self.ldb.search(expression="(!(|(revision=x)(dnsHostName=x)))", attrs=["dnsHostName", "lastLogon"]) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A")) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) self.assertTrue(not "dnsHostName" in res[1]) - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[2]["dnsHostName"]), "z") + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[2]) self.assertEquals(str(res[2]["lastLogon"]), "z") - self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[3]) + self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[3]["dnsHostName"]), "z") self.assertEquals(str(res[3]["lastLogon"]), "z") # Search by negated disjunction of remote attributes res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 5) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y")) - self.assertEquals(str(res[0]["dnsHostName"]), "y") - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[1]["dnsHostName"]), "z") - self.assertEquals(str(res[1]["lastLogon"]), "z") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[2]) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[0]) + self.assertEquals(str(res[0]["lastLogon"]), "z") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y")) + self.assertEquals(str(res[1]["dnsHostName"]), "y") + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[2]["dnsHostName"]), "z") self.assertEquals(str(res[2]["lastLogon"]), "z") # Search by negated disjunction of local and remote attribute res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 5) + res = sorted(res, key=attrgetter('dn')) self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) self.assertEquals(str(res[0]["lastLogon"]), "x") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[1]["dnsHostName"]), "z") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C")) + self.assertTrue(not "dnsHostName" in res[1]) self.assertEquals(str(res[1]["lastLogon"]), "z") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[2]) + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[2]["dnsHostName"]), "z") self.assertEquals(str(res[2]["lastLogon"]), "z") # Search by complex parse tree res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=["dnsHostName", "lastLogon"]) self.assertEquals(len(res), 7) - self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B")) + res = sorted(res, key=attrgetter('dn')) + self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A")) self.assertTrue(not "dnsHostName" in res[0]) - self.assertEquals(str(res[0]["lastLogon"]), "y") - self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X")) - self.assertEquals(str(res[1]["dnsHostName"]), "x") - self.assertEquals(str(res[1]["lastLogon"]), "x") - self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A")) + self.assertEquals(str(res[0]["lastLogon"]), "x") + self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B")) + self.assertTrue(not "dnsHostName" in res[1]) + self.assertEquals(str(res[1]["lastLogon"]), "y") + self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C")) self.assertTrue(not "dnsHostName" in res[2]) - self.assertEquals(str(res[2]["lastLogon"]), "x") - self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z")) - self.assertEquals(str(res[3]["dnsHostName"]), "z") - self.assertEquals(str(res[3]["lastLogon"]), "z") - self.assertEquals(str(res[4].dn), self.samba4.dn("cn=C")) - self.assertTrue(not "dnsHostName" in res[4]) + self.assertEquals(str(res[2]["lastLogon"]), "z") + self.assertEquals(str(res[3].dn), self.samba4.dn("cn=X")) + self.assertEquals(str(res[3]["dnsHostName"]), "x") + self.assertEquals(str(res[3]["lastLogon"]), "x") + self.assertEquals(str(res[4].dn), self.samba4.dn("cn=Z")) + self.assertEquals(str(res[4]["dnsHostName"]), "z") self.assertEquals(str(res[4]["lastLogon"]), "z") # Clean up -- cgit From 087ee1f40e4821f719f592ef2b768afad5c9a175 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 12 May 2011 22:53:26 +0200 Subject: s4-gpo: fixed display of GPO version numbers --- source4/scripting/python/samba/netcmd/gpo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/gpo.py b/source4/scripting/python/samba/netcmd/gpo.py index 19007b361c..fac9167076 100644 --- a/source4/scripting/python/samba/netcmd/gpo.py +++ b/source4/scripting/python/samba/netcmd/gpo.py @@ -126,7 +126,7 @@ class cmd_listall(Command): print("display name : %s" % m['displayName'][0]) print("path : %s" % m['gPCFileSysPath'][0]) print("dn : %s" % m.dn) - print("version : %s" % attr_default(m, 'version', '0')) + print("version : %s" % attr_default(m, 'versionNumber', '0')) print("flags : %s" % flags_string(gpo_flags, int(attr_default(m, 'flags', 0)))) print("") -- cgit From 40dc94a53f4f0f5dee285daf486912b0996d5f3e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 2 Jun 2011 15:40:28 +1000 Subject: s4-ipv6: update callers to load_interface_list() --- source4/scripting/python/pyglue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c index 0f2048aa89..8a82f3502a 100644 --- a/source4/scripting/python/pyglue.c +++ b/source4/scripting/python/pyglue.c @@ -153,7 +153,7 @@ static PyObject *py_interface_ips(PyObject *self, PyObject *args) return NULL; } - load_interface_list(tmp_ctx, lpcfg_interfaces(lp_ctx), &ifaces); + load_interface_list(tmp_ctx, lp_ctx, &ifaces); count = iface_list_count(ifaces); -- cgit From 7d59e9c549933c33182fbb0a7227be0eb69b4892 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 2 Jun 2011 17:09:17 +1000 Subject: s4-ipv6: added IPv6 support to samba_dnsupdate --- source4/scripting/bin/samba_dnsupdate | 38 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate index e86fba2983..cefe3ce859 100755 --- a/source4/scripting/bin/samba_dnsupdate +++ b/source4/scripting/bin/samba_dnsupdate @@ -89,6 +89,15 @@ if len(IPs) == 0: print "No IP interfaces - skipping DNS updates" sys.exit(0) +IP6s = [] +IP4s = [] +for i in IPs: + if i.find(':') != -1: + IP6s.append(i) + else: + IP4s.append(i) + + if opts.verbose: print "IPs: %s" % IPs @@ -122,7 +131,7 @@ class dnsobj(object): if self.type == 'SRV': self.dest = list[2].lower() self.port = list[3] - elif self.type == 'A': + elif self.type in ['A', 'AAAA']: self.ip = list[2] # usually $IP, which gets replaced elif self.type == 'CNAME': self.dest = list[2].lower() @@ -132,6 +141,7 @@ class dnsobj(object): def __str__(self): if d.type == "A": return "%s %s %s" % (self.type, self.name, self.ip) + if d.type == "AAAA": return "%s %s %s" % (self.type, self.name, self.ip) if d.type == "SRV": return "%s %s %s %s" % (self.type, self.name, self.dest, self.port) if d.type == "CNAME": return "%s %s %s" % (self.type, self.name, self.dest) @@ -178,7 +188,7 @@ def check_dns_name(d): if opts.verbose: print "Failed to find DNS entry %s" % d return False - if d.type == 'A': + if d.type in ['A', 'AAAA']: # we need to be sure that our IP is there for rdata in ans: if str(rdata) == str(d.ip): @@ -247,6 +257,8 @@ def call_nsupdate(d): f = os.fdopen(tmp_fd, 'w') if d.type == "A": f.write("update add %s %u A %s\n" % (normalised_name, default_ttl, d.ip)) + if d.type == "AAAA": + f.write("update add %s %u AAAA %s\n" % (normalised_name, default_ttl, d.ip)) if d.type == "SRV": if d.existing_port is not None: f.write("update delete %s SRV 0 %s %s %s\n" % (normalised_name, d.existing_weight, @@ -382,16 +394,28 @@ for line in file: if line == '' or line[0] == "#": continue d = parse_dns_line(line, sub_vars) + if d.type == 'A' and len(IP4s) == 0: + continue + if d.type == 'AAAA' and len(IP6s) == 0: + continue dns_list.append(d) # now expand the entries, if any are A record with ip set to $IP # then replace with multiple entries, one for each interface IP for d in dns_list: - if d.type == 'A' and d.ip == "$IP": - d.ip = IPs[0] - for i in range(len(IPs)-1): + if d.ip != "$IP": + continue + if d.type == 'A': + d.ip = IP4s[0] + for i in range(len(IP4s)-1): + d2 = dnsobj(str(d)) + d2.ip = IP4s[i+1] + dns_list.append(d2) + if d.type == 'AAAA': + d.ip = IP6s[0] + for i in range(len(IP6s)-1): d2 = dnsobj(str(d)) - d2.ip = IPs[i+1] + d2.ip = IP6s[i+1] dns_list.append(d2) # now check if the entries already exist on the DNS server @@ -412,7 +436,7 @@ for d in update_list: if am_rodc: if d.name.lower() == domain.lower(): continue - if d.type != 'A': + if not d.type in [ 'A', 'AAAA' ]: call_rodc_update(d) else: call_nsupdate(d) -- cgit From c4e43f9dff108f762eb1f7271ddb896b9b22e478 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 3 Jun 2011 11:43:09 +1000 Subject: s4-ipv6: don't add link local addresses to DNS these make no sense as DNS addresses --- source4/scripting/bin/samba_dnsupdate | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate index cefe3ce859..c82e06bb6f 100755 --- a/source4/scripting/bin/samba_dnsupdate +++ b/source4/scripting/bin/samba_dnsupdate @@ -93,7 +93,9 @@ IP6s = [] IP4s = [] for i in IPs: if i.find(':') != -1: - IP6s.append(i) + if i.find('%') == -1: + # we don't want link local addresses for DNS updates + IP6s.append(i) else: IP4s.append(i) -- cgit From 0e1d7eb429a3c6b34ed659f86b8d7a92434acd37 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 4 Jun 2011 08:20:54 +1000 Subject: s4-testparm: testparm is now part of samba_tool --- source4/scripting/bin/setup_dns.sh | 2 +- source4/scripting/bin/testparm | 219 ------------------------------------- source4/scripting/wscript_build | 2 - 3 files changed, 1 insertion(+), 222 deletions(-) delete mode 100755 source4/scripting/bin/testparm (limited to 'source4/scripting') diff --git a/source4/scripting/bin/setup_dns.sh b/source4/scripting/bin/setup_dns.sh index de4485fc07..646ee81f26 100755 --- a/source4/scripting/bin/setup_dns.sh +++ b/source4/scripting/bin/setup_dns.sh @@ -13,7 +13,7 @@ IP="$3" RSUFFIX=$(echo $DOMAIN | sed s/[\.]/,DC=/g) [ -z "$PRIVATEDIR" ] && { - PRIVATEDIR=$(bin/testparm --section-name=global --parameter-name='private dir' --suppress-prompt 2> /dev/null) + PRIVATEDIR=$(bin/samba_tool testparm --section-name=global --parameter-name='private dir' --suppress-prompt 2> /dev/null) } OBJECTGUID=$(bin/ldbsearch -s base -H "$PRIVATEDIR/sam.ldb" -b "CN=NTDS Settings,CN=$HOSTNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=$RSUFFIX" objectguid|grep ^objectGUID| cut -d: -f2) diff --git a/source4/scripting/bin/testparm b/source4/scripting/bin/testparm deleted file mode 100755 index c30e46148c..0000000000 --- a/source4/scripting/bin/testparm +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python -# vim: expandtab ft=python -# -# Unix SMB/CIFS implementation. -# Test validity of smb.conf -# Copyright (C) Karl Auer 1993, 1994-1998 -# -# Extensively modified by Andrew Tridgell, 1995 -# Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002 -# Updated for Samba4 by Andrew Bartlett 2006 -# Converted to Python by Jelmer Vernooij 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 . -# -# Testbed for loadparm.c/params.c -# -# This module simply loads a specified configuration file and -# if successful, dumps it's contents to stdout. Note that the -# operation is performed with DEBUGLEVEL at 3. -# -# Useful for a quick 'syntax check' of a configuration file. -# - -import logging -import optparse -import os -import sys - -# Find right directory when running from source tree -sys.path.insert(0, "bin/python") - -import samba -from samba import getopt as options - -# Here we do a set of 'hard coded' checks for bad -# configuration settings. - -def do_global_checks(lp, logger): - valid = True - - netbios_name = lp.get("netbios name") - if not samba.valid_netbios_name(netbios_name): - logger.error("netbios name %s is not a valid netbios name", - netbios_name) - valid = False - - workgroup = lp.get("workgroup") - if not samba.valid_netbios_name(workgroup): - logger.error("workgroup name %s is not a valid netbios name", - workgroup) - valid = False - - lockdir = lp.get("lockdir") - - if not os.path.isdir(lockdir): - logger.error("lock directory %s does not exist", lockdir) - valid = False - - piddir = lp.get("pid directory") - - if not os.path.isdir(piddir): - logger.error("pid directory %s does not exist", piddir) - valid = False - - winbind_separator = lp.get("winbind separator") - - if len(winbind_separator) != 1: - logger.error("the 'winbind separator' parameter must be a single " - "character.") - valid = False - - if winbind_separator == '+': - logger.error("'winbind separator = +' might cause problems with group " - "membership.") - valid = False - - return valid - - -def allow_access(deny_list, allow_list, cname, caddr): - raise NotImplementedError(allow_access) - - -def do_share_checks(lp, logger): - valid = True - for s in lp.services(): - if len(s) > 12: - logger.warning("You have some share names that are longer than 12 " - "characters. These may not be accessible to some older " - "clients. (Eg. Windows9x, WindowsMe, and not listed in " - "smbclient in Samba 3.0.)") - break - - for s in lp.services(): - deny_list = lp.get("hosts deny", s) - allow_list = lp.get("hosts allow", s) - if deny_list: - for entry in deny_list: - if "*" in entry or "?" in entry: - logger.error("Invalid character (* or ?) in hosts deny " - "list (%s) for service %s.", entry, s) - valid = False - - if allow_list: - for entry in allow_list: - if "*" in entry or "?" in entry: - logger.error("Invalid character (* or ?) in hosts allow " - "list (%s) for service %s.", entry, s) - valid = False - return valid - -def check_client_access(lp, cname, caddr): - # this is totally ugly, a real `quick' hack - for s in lp.services(): - if (allow_access(lp.get("hosts deny"), lp.get("hosts allow"), cname, - caddr) and - allow_access(lp.get("hosts deny", s), lp.get("hosts allow", s), - cname, caddr)): - logger.info("Allow connection from %s (%s) to %s", cname, caddr, s) - else: - logger.info("Deny connection from %s (%s) to %s", cname, caddr, s) - - -if __name__ == '__main__': - parser = optparse.OptionParser("testparm [OPTION...] [host-name] [host-ip]") - parser.add_option("--section-name", type="string", metavar="SECTION", - help="Limit testparm to a named section") - parser.add_option("--parameter-name", type="string", metavar="PARAMETER", - help="Limit testparm to a named parameter") - parser.add_option("--client-name", type="string", metavar="HOSTNAME", - help="Client DNS name for 'hosts allow' checking " - "(should match reverse lookup)") - parser.add_option("--client-ip", type="string", metavar="IP", - help="Client IP address for 'hosts allow' checking") - parser.add_option("--suppress-prompt", action="store_true", default=False, - help="Suppress prompt for enter") - parser.add_option("-v", "--verbose", action="store_true", - default=False, help="Show default options too") - parser.add_option_group(options.VersionOptions(parser)) - # We need support for smb.conf macros before this will work again - parser.add_option("--server", type="string", - help="Set %%L macro to servername") - # These are harder to do with the new code structure - parser.add_option("--show-all-parameters", action="store_true", - default=False, help="Show the parameters, type, possible values") - - sambaopts = options.SambaOptions(parser) - parser.add_option_group(sambaopts) - - opts, args = parser.parse_args() - -# -# if (show_all_parameters) { -# show_parameter_list() -# exit(0) -# } - - if len(args) > 0: - cname = args[0] - else: - cname = None - if len(args) > 1: - caddr = args[1] - else: - caddr = None - - if cname is not None and caddr is None: - print "Both a DNS name and an IP address are required for the host " \ - "access check." - sys.exit(1) - -# FIXME: We need support for smb.conf macros before this will work again -# -# if (new_local_machine) { -# set_local_machine_name(new_local_machine, True) -# } - - lp = sambaopts.get_loadparm() - - # We need this to force the output - samba.set_debug_level(2) - - logger = logging.getLogger("testparm") - logger.addHandler(logging.StreamHandler(sys.stdout)) - - logger.info("Loaded smb config files from %s", lp.configfile) - logger.info("Loaded services file OK.") - - valid = do_global_checks(lp, logger) - valid = valid and do_share_checks(lp, logger) - if cname is not None: - check_client_access(lp, cname, caddr) - else: - if opts.section_name is not None or opts.parameter_name is not None: - if opts.parameter_name is None: - lp[opts.section_name].dump(sys.stdout, lp.default_service, - opts.verbose) - else: - print lp.get(opts.parameter_name, opts.section_name) - else: - if not opts.suppress_prompt: - print "Press enter to see a dump of your service definitions\n" - sys.stdin.readline() - lp.dump(sys.stdout, opts.verbose) - if valid: - sys.exit(0) - else: - sys.exit(1) diff --git a/source4/scripting/wscript_build b/source4/scripting/wscript_build index 76ff739c9e..03f188f7fa 100644 --- a/source4/scripting/wscript_build +++ b/source4/scripting/wscript_build @@ -4,5 +4,3 @@ from samba_utils import MODE_755 bld.INSTALL_FILES('${SBINDIR}','bin/upgradeprovision bin/samba_dnsupdate bin/samba_spnupdate', chmod=MODE_755, python_fixup=True, flat=True) -bld.INSTALL_FILES('${BINDIR}','bin/testparm', - chmod=MODE_755, python_fixup=True, flat=True) -- cgit From 473b3446998ca49e6597e30f8bbca43fd7215769 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 4 Jun 2011 08:22:30 +1000 Subject: s4-script: install some of the samba scripts in bin/ during build --- source4/scripting/bin/wscript_build | 5 +++++ source4/scripting/wscript_build | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 source4/scripting/bin/wscript_build (limited to 'source4/scripting') diff --git a/source4/scripting/bin/wscript_build b/source4/scripting/bin/wscript_build new file mode 100644 index 0000000000..e52b32bc02 --- /dev/null +++ b/source4/scripting/bin/wscript_build @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +bld.SAMBA_SCRIPT('samba_dnsupdate', pattern='samba_dnsupdate', installdir='.') +bld.SAMBA_SCRIPT('samba_spnupdate', pattern='samba_spnupdate', installdir='.') +bld.SAMBA_SCRIPT('upgradeprovision', pattern='upgradeprovision', installdir='.') diff --git a/source4/scripting/wscript_build b/source4/scripting/wscript_build index 03f188f7fa..d94fc4fe9c 100644 --- a/source4/scripting/wscript_build +++ b/source4/scripting/wscript_build @@ -4,3 +4,5 @@ from samba_utils import MODE_755 bld.INSTALL_FILES('${SBINDIR}','bin/upgradeprovision bin/samba_dnsupdate bin/samba_spnupdate', chmod=MODE_755, python_fixup=True, flat=True) + +bld.RECURSE('bin') -- cgit From c091a92be51e8c14bf0b51ab83319fbcb704c91f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 2 Jun 2011 15:43:40 +1000 Subject: s4-param Remove 'sam database' parameter This now just relies on the private dir parameter, which remains. Andrew Bartlett --- source4/scripting/bin/samba_dnsupdate | 2 +- source4/scripting/bin/samba_spnupdate | 4 ++-- source4/scripting/python/samba/hostconfig.py | 2 +- source4/scripting/python/samba/provision/__init__.py | 5 ++--- source4/scripting/python/samba/samdb.py | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate index c82e06bb6f..0a13dd7c9b 100755 --- a/source4/scripting/bin/samba_dnsupdate +++ b/source4/scripting/bin/samba_dnsupdate @@ -222,7 +222,7 @@ def get_subst_vars(): global lp, am_rodc vars = {} - samdb = SamDB(url=lp.get("sam database"), session_info=system_session(), + samdb = SamDB(url=lp.samdb_url(), session_info=system_session(), lp=lp) vars['DNSDOMAIN'] = lp.get('realm').lower() diff --git a/source4/scripting/bin/samba_spnupdate b/source4/scripting/bin/samba_spnupdate index 1794f2bd26..fe3fcfc675 100755 --- a/source4/scripting/bin/samba_spnupdate +++ b/source4/scripting/bin/samba_spnupdate @@ -103,9 +103,9 @@ try: else: credentials = None - samdb = SamDB(url=lp.get("sam database"), session_info=system_session(), credentials=credentials, lp=lp) + samdb = SamDB(url=lp.samdb_url(), session_info=system_session(), credentials=credentials, lp=lp) except ldb.LdbError, (num, msg): - print("Unable to open sam database %s : %s" % (lp.get("sam database"), msg)) + print("Unable to open sam database %s : %s" % (lp.samdb_url(), msg)) sys.exit(1) diff --git a/source4/scripting/python/samba/hostconfig.py b/source4/scripting/python/samba/hostconfig.py index 3e6dc6b1dd..c50b944c98 100644 --- a/source4/scripting/python/samba/hostconfig.py +++ b/source4/scripting/python/samba/hostconfig.py @@ -37,7 +37,7 @@ class Hostconfig(object): :param session_info: Session info to use :param credentials: Credentials to access the SamDB with """ - return SamDB(url=self.lp.get("sam database"), + return SamDB(url=self.lp.samdb_url(), session_info=session_info, credentials=credentials, lp=self.lp) diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index f987fb8ef3..fffd352071 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -432,7 +432,7 @@ def check_install(lp, session_info, credentials): """ if lp.get("realm") == "": raise Exception("Realm empty") - samdb = Ldb(lp.get("sam database"), session_info=session_info, + samdb = Ldb(lp.samdb_url(), session_info=session_info, credentials=credentials, lp=lp) if len(samdb.search("(cn=Administrator)")) != 1: raise ProvisioningError("No administrator account found") @@ -517,8 +517,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.keytab = "secrets.keytab" paths.shareconf = os.path.join(paths.private_dir, "share.ldb") - paths.samdb = os.path.join(paths.private_dir, - lp.get("sam database") or "samdb.ldb") + paths.samdb = os.path.join(paths.private_dir, "sam.ldb") paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb") paths.secrets = os.path.join(paths.private_dir, diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index a5c627e5b5..55f3536c27 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -46,7 +46,7 @@ class SamDB(samba.Ldb): if not auto_connect: url = None elif url is None and lp is not None: - url = lp.get("sam database") + url = lp.samdb_url() super(SamDB, self).__init__(url=url, lp=lp, modules_dir=modules_dir, session_info=session_info, credentials=credentials, flags=flags, -- cgit From 1565da76947f91add10a54096cdfe2ab67917b32 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 2 Jun 2011 15:47:44 +1000 Subject: s4-param Remove 'secrets database' parameter This is now just secrets.ldb in the private dir, which remains. --- source4/scripting/bin/samba_spnupdate | 2 +- source4/scripting/python/samba/provision/__init__.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/samba_spnupdate b/source4/scripting/bin/samba_spnupdate index fe3fcfc675..9f8f4073d3 100755 --- a/source4/scripting/bin/samba_spnupdate +++ b/source4/scripting/bin/samba_spnupdate @@ -82,7 +82,7 @@ def get_subst_vars(samdb): try: private_dir = lp.get("private dir") - secrets_path = os.path.join(private_dir, lp.get("secrets database")) + secrets_path = os.path.join(private_dir, "secrets.ldb") secrets_db = Ldb(url=secrets_path, session_info=system_session(), credentials=creds, lp=lp) diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index fffd352071..b99eec9ab8 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -520,8 +520,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.samdb = os.path.join(paths.private_dir, "sam.ldb") paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb") - paths.secrets = os.path.join(paths.private_dir, - lp.get("secrets database") or "secrets.ldb") + paths.secrets = os.path.join(paths.private_dir, "secrets.ldb") paths.privilege = os.path.join(paths.private_dir, "privilege.ldb") paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone") paths.dns_update_list = os.path.join(paths.private_dir, "dns_update_list") -- cgit From 834d590bcff79e2d458b9e193be0c64e849a6362 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 2 Jun 2011 15:49:36 +1000 Subject: s4-param Remove 'idmap database' This is now just idmap.ldb in the private dir, which remains. --- source4/scripting/python/samba/idmap.py | 2 +- source4/scripting/python/samba/provision/__init__.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py index 93fca46edd..9d957341de 100644 --- a/source4/scripting/python/samba/idmap.py +++ b/source4/scripting/python/samba/idmap.py @@ -41,7 +41,7 @@ class IDmapDB(samba.Ldb): self.lp = lp if url is None: - url = lp.get("idmap database") + url = lp.private_path("idmap.ldb") super(IDmapDB, self).__init__(url=url, lp=lp, modules_dir=modules_dir, session_info=session_info, credentials=credentials, flags=flags, diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index b99eec9ab8..bd3ab8a4f4 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -518,8 +518,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.shareconf = os.path.join(paths.private_dir, "share.ldb") paths.samdb = os.path.join(paths.private_dir, "sam.ldb") - paths.idmapdb = os.path.join(paths.private_dir, - lp.get("idmap database") or "idmap.ldb") + paths.idmapdb = os.path.join(paths.private_dir, "idmap.ldb") paths.secrets = os.path.join(paths.private_dir, "secrets.ldb") paths.privilege = os.path.join(paths.private_dir, "privilege.ldb") paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone") -- cgit From a18efb1490cebd92205973c50ce1582b091a7676 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 2 Jun 2011 18:56:10 +1000 Subject: s4-param Remove 'sid generator' This was only used by the Fedora DS backend for Samba4. We agreed to no longer support external LDAP backends. Andrew Bartlett --- source4/scripting/python/samba/provision/__init__.py | 6 ------ source4/scripting/python/samba/tests/samba3sam.py | 6 +++++- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index bd3ab8a4f4..eb6e01f389 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -709,11 +709,6 @@ def make_smbconf(smbconf, hostname, domain, realm, serverrole, privatedir_line = "" lockdir_line = "" - if sid_generator == "internal": - sid_generator_line = "" - else: - sid_generator_line = "sid generator = " + sid_generator - sysvol = os.path.join(lp.get("lock dir"), "sysvol") netlogon = os.path.join(sysvol, realm.lower(), "scripts") @@ -725,7 +720,6 @@ def make_smbconf(smbconf, hostname, domain, realm, serverrole, "SERVERROLE": serverrole, "NETLOGONPATH": netlogon, "SYSVOLPATH": sysvol, - "SIDGENERATOR_LINE": sid_generator_line, "PRIVATEDIR_LINE": privatedir_line, "LOCKDIR_LINE": lockdir_line }) diff --git a/source4/scripting/python/samba/tests/samba3sam.py b/source4/scripting/python/samba/tests/samba3sam.py index 99b9c0655e..7353391519 100644 --- a/source4/scripting/python/samba/tests/samba3sam.py +++ b/source4/scripting/python/samba/tests/samba3sam.py @@ -65,7 +65,6 @@ class MapBaseTestCase(TestCaseInTempDir): def setUp(self): self.lp = env_loadparm() - self.lp.set("sid generator", "backend") self.lp.set("workgroup", "TESTS") self.lp.set("netbios name", "TESTS") super(MapBaseTestCase, self).setUp() @@ -87,6 +86,7 @@ class MapBaseTestCase(TestCaseInTempDir): def __init__(self, basedn, dn, lp): self.db = Ldb(lp=lp, session_info=system_session()) + self.db.set_opaque("skip_allocate_sids", "true"); self.basedn = basedn self.basedn_casefold = ldb.Dn(self.db, basedn).get_casefold() self.substvars = {"BASEDN": self.basedn} @@ -136,12 +136,14 @@ class Samba3SamTestCase(MapBaseTestCase): def setUp(self): super(Samba3SamTestCase, self).setUp() ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) + ldb.set_opaque("skip_allocate_sids", "true"); self.samba3.setup_data("samba3.ldif") ldif = read_datafile("provision_samba3sam.ldif") ldb.add_ldif(self.samba4.subst(ldif)) self.setup_modules(ldb, self.samba3, self.samba4) del ldb self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) + self.ldb.set_opaque("skip_allocate_sids", "true"); def test_search_non_mapped(self): """Looking up by non-mapped attribute""" @@ -303,11 +305,13 @@ class MapTestCase(MapBaseTestCase): def setUp(self): super(MapTestCase, self).setUp() ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) + ldb.set_opaque("skip_allocate_sids", "true"); ldif = read_datafile("provision_samba3sam.ldif") ldb.add_ldif(self.samba4.subst(ldif)) self.setup_modules(ldb, self.samba3, self.samba4) del ldb self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session()) + self.ldb.set_opaque("skip_allocate_sids", "true"); def test_map_search(self): """Running search tests on mapped data.""" -- cgit From f67a14976bd6ccdacd319df872e6add994f0e0f3 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 6 Jun 2011 14:39:19 +1000 Subject: s4-param Remove 'modules dir' The Samba waf build ensures that dyn_MODULESDIR is always correct (even for in-tree binaries), so we don't need to allow the user to configure this at run time. Andrew Bartlett --- source4/scripting/python/samba/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index dac69e7f62..76eb44ce92 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -26,6 +26,7 @@ __docformat__ = "restructuredText" import os import sys +import samba.param def source_tree_topdir(): '''return the top level directory (the one containing the source4 directory)''' @@ -77,8 +78,8 @@ class Ldb(_Ldb): if modules_dir is not None: self.set_modules_dir(modules_dir) - elif lp is not None: - self.set_modules_dir(os.path.join(lp.get("modules dir"), "ldb")) + else: + self.set_modules_dir(os.path.join(samba.param.modules_dir(), "ldb")) if session_info is not None: self.set_session_info(session_info) -- cgit From 8acbc3a17435ef330910993aa40b5ec1e4c1dab2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 7 Jun 2011 12:55:31 +1000 Subject: s4-provision: fixed detection of V4/V6 addresses Autobuild-User: Andrew Tridgell Autobuild-Date: Tue Jun 7 06:07:24 CEST 2011 on sn-devel-104 --- .../scripting/python/samba/provision/__init__.py | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index eb6e01f389..324e76f374 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -1465,6 +1465,25 @@ def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn, set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp) +def interface_ips_v4(lp): + '''return only IPv4 IPs''' + ips = samba.interface_ips(lp, False) + ret = [] + for i in ips: + if i.find(':') == -1: + ret.append(i) + return ret + +def interface_ips_v6(lp, linklocal=False): + '''return only IPv6 IPs''' + ips = samba.interface_ips(lp, False) + ret = [] + for i in ips: + if i.find(':') != -1 and (linklocal or i.find('%') == -1): + ret.append(i) + return ret + + def provision(logger, session_info, credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None, serverdn=None, @@ -1565,16 +1584,24 @@ def provision(logger, session_info, credentials, smbconf=None, if hostip is None: logger.info("Looking up IPv4 addresses") - hostips = samba.interface_ips(lp, False) + hostips = interface_ips_v4(lp) if len(hostips) == 0: logger.warning("No external IPv4 address has been found. Using loopback.") hostip = '127.0.0.1' else: hostip = hostips[0] if len(hostips) > 1: - logger.warning("More than one IPv4 address found. Using %s.", + logger.warning("More than one IPv4 address found. Using %s", hostip) + if hostip6 is None: + logger.info("Looking up IPv6 addresses") + hostips = interface_ips_v6(lp, linklocal=False) + if hostips: + hostip6 = hostips[0] + if len(hostips) > 1: + logger.warning("More than one IPv6 address found. Using %s", hostip6) + if serverrole is None: serverrole = lp.get("server role") -- cgit From a58e69a734085f9963b60042be3d9a33a90616a7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 7 Jun 2011 13:46:24 +1000 Subject: s4-dns: fixed samba_tool -> samba-tool --- source4/scripting/bin/setup_dns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/setup_dns.sh b/source4/scripting/bin/setup_dns.sh index 646ee81f26..bc2ae96b84 100755 --- a/source4/scripting/bin/setup_dns.sh +++ b/source4/scripting/bin/setup_dns.sh @@ -13,7 +13,7 @@ IP="$3" RSUFFIX=$(echo $DOMAIN | sed s/[\.]/,DC=/g) [ -z "$PRIVATEDIR" ] && { - PRIVATEDIR=$(bin/samba_tool testparm --section-name=global --parameter-name='private dir' --suppress-prompt 2> /dev/null) + PRIVATEDIR=$(bin/samba-tool testparm --section-name=global --parameter-name='private dir' --suppress-prompt 2> /dev/null) } OBJECTGUID=$(bin/ldbsearch -s base -H "$PRIVATEDIR/sam.ldb" -b "CN=NTDS Settings,CN=$HOSTNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=$RSUFFIX" objectguid|grep ^objectGUID| cut -d: -f2) -- cgit From 1596595b7e644de6432d7c8fb9e10ee2b525440e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 9 Jun 2011 15:00:03 +1000 Subject: s4-ipv6: don't default to 127.0.0.1 in provision it is better to just leave the IPv4 address out of the zone file Pair-Programmed-With: Andrew Bartlett --- source4/scripting/python/samba/provision/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index 324e76f374..f272872a93 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -1585,14 +1585,15 @@ def provision(logger, session_info, credentials, smbconf=None, if hostip is None: logger.info("Looking up IPv4 addresses") hostips = interface_ips_v4(lp) - if len(hostips) == 0: - logger.warning("No external IPv4 address has been found. Using loopback.") - hostip = '127.0.0.1' - else: + if len(hostips) > 0: hostip = hostips[0] if len(hostips) > 1: logger.warning("More than one IPv4 address found. Using %s", hostip) + if hostip == "127.0.0.1": + hostip = None + if hostip is None: + logger.warning("No IPv4 address will be assigned") if hostip6 is None: logger.info("Looking up IPv6 addresses") @@ -1601,6 +1602,8 @@ def provision(logger, session_info, credentials, smbconf=None, hostip6 = hostips[0] if len(hostips) > 1: logger.warning("More than one IPv6 address found. Using %s", hostip6) + if hostip6 is None: + logger.warning("No IPv6 address will be assigned") if serverrole is None: serverrole = lp.get("server role") @@ -1868,7 +1871,7 @@ def provision_become_dc(smbconf=None, targetdir=None, smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, serverdn=serverdn, domain=domain, - hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, + hostname=hostname, hostip=None, domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename) res.lp.set("debuglevel", str(debuglevel)) -- cgit From 516dc404fd7f299b68adae356f2416ca8e265031 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 9 Jun 2011 15:01:30 +1000 Subject: samba-tool: added --local option to drs replicate command this allows replication directly to the local SAM, which means it can run without the samba daemon running. It also bypasses all usnChanged checks, which is useful for forcing replication of a set of objects which are not marked as replication being needed Autobuild-User: Andrew Tridgell Autobuild-Date: Thu Jun 9 08:15:10 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/netcmd/drs.py | 40 +++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/drs.py b/source4/scripting/python/samba/netcmd/drs.py index 56c0e39a59..61717a70e9 100644 --- a/source4/scripting/python/samba/netcmd/drs.py +++ b/source4/scripting/python/samba/netcmd/drs.py @@ -233,6 +233,39 @@ class cmd_drs_kcc(Command): self.message("Consistency check on %s successful." % DC) +def drs_local_replicate(self, SOURCE_DC, NC): + '''replicate from a source DC to the local SAM''' + self.server = SOURCE_DC + drsuapi_connect(self) + + self.local_samdb = SamDB(session_info=system_session(), url=None, + credentials=self.creds, lp=self.lp) + + self.samdb = SamDB(url="ldap://%s" % self.server, + session_info=system_session(), + credentials=self.creds, lp=self.lp) + + # work out the source and destination GUIDs + res = self.local_samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"]) + self.ntds_dn = res[0]["dsServiceName"][0] + + res = self.local_samdb.search(base=self.ntds_dn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"]) + self.ntds_guid = misc.GUID(self.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0])) + + + source_dsa_invocation_id = misc.GUID(self.samdb.get_invocation_id()) + destination_dsa_guid = self.ntds_guid + + self.samdb.transaction_start() + repl = drs_utils.drs_Replicate("ncacn_ip_tcp:%s[seal]" % self.server, self.lp, + self.creds, self.local_samdb) + try: + repl.replicate(NC, source_dsa_invocation_id, destination_dsa_guid) + except Exception, e: + raise CommandError("Error replicating DN %s" % NC, e) + self.samdb.transaction_commit() + + class cmd_drs_replicate(Command): """replicate a naming context between two DCs""" @@ -250,9 +283,10 @@ class cmd_drs_replicate(Command): takes_options = [ Option("--add-ref", help="use ADD_REF to add to repsTo on source", action="store_true"), Option("--sync-forced", help="use SYNC_FORCED to force inbound replication", action="store_true"), + Option("--local", help="pull changes directly into the local database (destination DC is ignored)", action="store_true"), ] - def run(self, DEST_DC, SOURCE_DC, NC, add_ref=False, sync_forced=False, + def run(self, DEST_DC, SOURCE_DC, NC, add_ref=False, sync_forced=False, local=False, sambaopts=None, credopts=None, versionopts=None, server=None): @@ -261,6 +295,10 @@ class cmd_drs_replicate(Command): self.creds = credopts.get_credentials(self.lp, fallback_machine=True) + if local: + drs_local_replicate(self, SOURCE_DC, NC) + return + drsuapi_connect(self) samdb_connect(self) -- cgit From 0c89d624e6d5620c9e37649cc2976aba918b1e6a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 10 Jun 2011 17:17:12 +1000 Subject: s4-samba-tool: added dbcheck commmand this will be used as a consistency checker and repair tool for sam.ldb. This initial checkin just checks for empty attributes and offers to fix them Autobuild-User: Andrew Tridgell Autobuild-Date: Fri Jun 10 10:31:56 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/netcmd/__init__.py | 2 + source4/scripting/python/samba/netcmd/dbcheck.py | 123 ++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 source4/scripting/python/samba/netcmd/dbcheck.py (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index d934cf8af6..1373cb289b 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -212,3 +212,5 @@ from samba.netcmd.ldapcmp import cmd_ldapcmp commands["ldapcmp"] = cmd_ldapcmp() from samba.netcmd.testparm import cmd_testparm commands["testparm"] = cmd_testparm() +from samba.netcmd.dbcheck import cmd_dbcheck +commands["dbcheck"] = cmd_dbcheck() diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py new file mode 100644 index 0000000000..7bbd4d21b6 --- /dev/null +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# +# Samba4 AD database checker +# +# Copyright (C) Andrew Tridgell 2011 +# +# 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 . +# + +import samba, ldb +import samba.getopt as options +from samba.auth import system_session +from samba.samdb import SamDB +from samba.dcerpc import security +from samba.netcmd import ( + Command, + CommandError, + Option + ) + +def confirm(self, msg): + '''confirm an action with the user''' + if self.yes: + print("%s [YES]" % msg) + return True + v = raw_input(msg + ' [y/N] ') + return v.upper() in ['Y', 'YES'] + + +def empty_attribute(self, dn, attrname): + '''fix empty attributes''' + print("ERROR: Empty attribute %s in %s" % (attrname, dn)) + if not self.fix: + return + if not confirm(self, 'Remove empty attribute %s from %s?' % (attrname, dn)): + print("Not fixing empty attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) + try: + self.samdb.modify(m, ["relax:0"]) + except Exception, msg: + print("Failed to remove empty attribute %s : %s" % (attrname, msg)) + return + print("Removed empty attribute %s" % attrname) + + + +def check_object(self, dn): + '''check one object''' + if self.verbose: + print("Checking object %s" % dn) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE) + if len(res) != 1: + print("Object %s disappeared during check" % dn) + return + obj = res[0] + for attrname in obj: + if attrname == 'dn': + continue + for val in obj[attrname]: + if val == '': + empty_attribute(self, dn, attrname) + continue + + +class cmd_dbcheck(Command): + """check local AD database for errors""" + synopsis = "dbcheck [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptionsDouble, + } + + takes_args = ["DN?"] + + takes_options = [ + Option("--scope", dest="scope", default="SUB", + help="Pass search scope that builds DN list. Options: SUB, ONE, BASE"), + Option("--fix", dest="fix", default=False, action='store_true', + help='Fix any errors found'), + Option("--yes", dest="yes", default=False, action='store_true', + help="don't confirm changes, just do them all"), + Option("-v", "--verbose", dest="verbose", action="store_true", default=False, + help="Print more details of checking"), + ] + + def run(self, DN=None, verbose=False, fix=False, yes=False, + scope="SUB", credopts=None, sambaopts=None, versionopts=None): + self.lp = sambaopts.get_loadparm() + self.creds = credopts.get_credentials(self.lp, fallback_machine=True) + + self.samdb = SamDB(session_info=system_session(), url=None, + credentials=self.creds, lp=self.lp) + self.verbose = verbose + self.fix = fix + self.yes = yes + + scope_map = { "SUB": ldb.SCOPE_SUBTREE, "BASE":ldb.SCOPE_BASE, "ONE":ldb.SCOPE_ONELEVEL } + scope = scope.upper() + if not scope in scope_map: + raise CommandError("Unknown scope %s" % scope) + self.search_scope = scope_map[scope] + + res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn']) + for object in res: + check_object(self, object.dn) + print('Checked %u objects' % len(res)) -- cgit From d575b2b0aba0aeaf73d82e2ed58150110db4025b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 14 Jun 2011 16:43:10 +1000 Subject: samba-tool: disable validation on removing an empty attribute in dbcheck Autobuild-User: Andrew Tridgell Autobuild-Date: Tue Jun 14 10:49:34 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/netcmd/dbcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 7bbd4d21b6..7af210104c 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -51,7 +51,7 @@ def empty_attribute(self, dn, attrname): m.dn = dn m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) try: - self.samdb.modify(m, ["relax:0"]) + self.samdb.modify(m, controls=["relax:0"], validate=False) except Exception, msg: print("Failed to remove empty attribute %s : %s" % (attrname, msg)) return -- cgit From 665ef94d3c15ba59811143bb3d3e395ffd306a58 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 11:29:44 +1000 Subject: s4-pydsdb: added dsdb_normalise_attributes() call this call converts a set of attributes to DRSUAPI format and back to ldb format. This has the effect of normalising the attributes using the schema syntax rules --- source4/scripting/python/samba/samdb.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 55f3536c27..b513ac8fff 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -507,8 +507,13 @@ accountExpires: %u dsdb._dsdb_set_schema_from_ldb(self, ldb_conn) def dsdb_DsReplicaAttribute(self, ldb, ldap_display_name, ldif_elements): + '''convert a list of attribute values to a DRSUAPI DsReplicaAttribute''' return dsdb._dsdb_DsReplicaAttribute(ldb, ldap_display_name, ldif_elements) + def dsdb_normalise_attributes(self, ldb, ldap_display_name, ldif_elements): + '''normalise a list of attribute values''' + return dsdb._dsdb_normalise_attributes(ldb, ldap_display_name, ldif_elements) + def get_attribute_from_attid(self, attid): """ Get from an attid the associated attribute -- cgit From 08dc1aa4cc1a697dd72db6a09a32d1929421fc09 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 11:31:25 +1000 Subject: samba-tool: added attribute normalisation checks this checks that all attributes have the right normalisation, and offers to fix the ones that don't --- source4/scripting/python/samba/netcmd/dbcheck.py | 56 ++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 7af210104c..4eebca3503 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -58,12 +58,46 @@ def empty_attribute(self, dn, attrname): print("Removed empty attribute %s" % attrname) +def normalise_mismatch(self, dn, attrname, values): + '''fix attribute normalisation errors''' + print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) + mod_list = [] + for val in values: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1: + print("Unable to normalise value '%s'" % val) + mod_list.append((val, '')) + elif (normalised[0] != val): + print("value '%s' should be '%s'" % (val, normalised[0])) + mod_list.append((val, normalised[0])) + if not self.fix: + return + if not confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): + print("Not fixing attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + for i in range(0, len(mod_list)): + (val, nval) = mod_list[i] + m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + if nval != '': + m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) + + try: + self.samdb.modify(m, controls=["relax:0"], validate=False) + except Exception, msg: + print("Failed to normalise attribute %s : %s" % (attrname, msg)) + return + print("Normalised attribute %s" % attrname) + + def check_object(self, dn): '''check one object''' if self.verbose: print("Checking object %s" % dn) - res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) if len(res) != 1: print("Object %s disappeared during check" % dn) return @@ -71,11 +105,20 @@ def check_object(self, dn): for attrname in obj: if attrname == 'dn': continue + + # check for empty attributes for val in obj[attrname]: if val == '': empty_attribute(self, dn, attrname) continue + # check for incorrectly normalised attributes + for val in obj[attrname]: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1 or normalised[0] != val: + normalise_mismatch(self, dn, attrname, obj[attrname]) + break + class cmd_dbcheck(Command): """check local AD database for errors""" @@ -96,11 +139,13 @@ class cmd_dbcheck(Command): help='Fix any errors found'), Option("--yes", dest="yes", default=False, action='store_true', help="don't confirm changes, just do them all"), + Option("--cross-ncs", dest="cross_ncs", default=False, action='store_true', + help="cross naming context boundaries"), Option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print more details of checking"), ] - def run(self, DN=None, verbose=False, fix=False, yes=False, + def run(self, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, scope="SUB", credopts=None, sambaopts=None, versionopts=None): self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp, fallback_machine=True) @@ -117,7 +162,12 @@ class cmd_dbcheck(Command): raise CommandError("Unknown scope %s" % scope) self.search_scope = scope_map[scope] - res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn']) + controls = [] + if cross_ncs: + controls.append("search_options:1:2") + + res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) + print('Checking %u objects' % len(res)) for object in res: check_object(self, object.dn) print('Checked %u objects' % len(res)) -- cgit From a8269792aa7c75b82b5ccab0e3b819601f7a4ef4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 11:34:19 +1000 Subject: samba-tool: report total error count and suggest --fix if needed --- source4/scripting/python/samba/netcmd/dbcheck.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 4eebca3503..9f12136de8 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -100,8 +100,9 @@ def check_object(self, dn): res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) if len(res) != 1: print("Object %s disappeared during check" % dn) - return + return 1 obj = res[0] + error_count = 0 for attrname in obj: if attrname == 'dn': continue @@ -110,6 +111,7 @@ def check_object(self, dn): for val in obj[attrname]: if val == '': empty_attribute(self, dn, attrname) + error_count += 1 continue # check for incorrectly normalised attributes @@ -117,7 +119,9 @@ def check_object(self, dn): normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) if len(normalised) != 1 or normalised[0] != val: normalise_mismatch(self, dn, attrname, obj[attrname]) + error_count += 1 break + return error_count class cmd_dbcheck(Command): @@ -168,6 +172,9 @@ class cmd_dbcheck(Command): res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) print('Checking %u objects' % len(res)) + error_count = 0 for object in res: - check_object(self, object.dn) - print('Checked %u objects' % len(res)) + error_count += check_object(self, object.dn) + if error_count != 0 and not self.fix: + print("Please use --fix to fix these errors") + print('Checked %u objects (%u errors)' % (len(res), error_count)) -- cgit From 0c3075cb57134f6171c332158c3052e05dace595 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 12:02:23 +1000 Subject: s4-pysamdb: fixed the normalisation of grouptype in group add ldap integers are signed Autobuild-User: Andrew Tridgell Autobuild-Date: Fri Jun 17 05:43:18 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/samdb.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index b513ac8fff..53346e8670 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -142,7 +142,7 @@ pwdLastSet: 0 "objectClass": "group"} if grouptype is not None: - ldbmessage["groupType"] = "%d" % grouptype + ldbmessage["groupType"] = self.normalise_int32(grouptype) if description is not None: ldbmessage["description"] = description @@ -722,3 +722,9 @@ accountExpires: %u if sd: m["nTSecurityDescriptor"] = ndr_pack(sd) self.add(m) + + def normalise_int32(self, ivalue): + '''normalise a ldap integer to signed 32 bit''' + if int(ivalue) & 0x80000000: + return str(int(ivalue) - 0x100000000) + return str(ivalue) -- cgit From 705ed1c4921a1456ebcf80ac352567679ab7dfa9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 13:35:52 +1000 Subject: samba-tool: show success message on group operations --- source4/scripting/python/samba/netcmd/group.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/group.py b/source4/scripting/python/samba/netcmd/group.py index 620a7be866..95db21adfc 100644 --- a/source4/scripting/python/samba/netcmd/group.py +++ b/source4/scripting/python/samba/netcmd/group.py @@ -85,6 +85,7 @@ class cmd_group_add(Command): description=description, mailaddress=mail_address, notes=notes) except Exception, e: raise CommandError('Failed to create group "%s"' % groupname, e) + print("Added group %s" % groupname) class cmd_group_delete(Command): @@ -115,6 +116,7 @@ class cmd_group_delete(Command): samdb.deletegroup(groupname) except Exception, e: raise CommandError('Failed to remove group "%s"' % groupname, e) + print("Deleted group %s" % groupname) class cmd_group_add_members(Command): @@ -146,6 +148,7 @@ class cmd_group_add_members(Command): samdb.add_remove_group_members(groupname, listofmembers, add_members_operation=True) except Exception, e: raise CommandError('Failed to add members "%s" to group "%s"' % (listofmembers, groupname), e) + print("Added members to group %s" % groupname) class cmd_group_remove_members(Command): @@ -177,6 +180,7 @@ class cmd_group_remove_members(Command): samdb.add_remove_group_members(groupname, listofmembers, add_members_operation=False) except Exception, e: raise CommandError('Failed to remove members "%s" from group "%s"' % (listofmembers, groupname), e) + print("Removed members from group %s" % groupname) class cmd_group(SuperCommand): -- cgit From 0b3b7e3797a9aa0dc8f0922c8cd873b0f0b3231e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 17 Jun 2011 14:40:48 +1000 Subject: samba-tool: exit with non-zero status on dbcheck failure Pair-Programmed-With: Andrew Bartlett --- source4/scripting/python/samba/netcmd/dbcheck.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 9f12136de8..b0d77f2fd9 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -18,7 +18,7 @@ # along with this program. If not, see . # -import samba, ldb +import samba, ldb, sys import samba.getopt as options from samba.auth import system_session from samba.samdb import SamDB @@ -178,3 +178,5 @@ class cmd_dbcheck(Command): if error_count != 0 and not self.fix: print("Please use --fix to fix these errors") print('Checked %u objects (%u errors)' % (len(res), error_count)) + if error_count != 0: + sys.exit(1) -- cgit From b14bdf431b49a674bceab7f8f81ae98d938b92f6 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 5 Jun 2011 17:26:07 +0400 Subject: s4-upgradeprovision: Fix an error, so that cursddl and refsddl are not the same Thanks to Dirk Paulli for pointing it with his bug report. --- source4/scripting/bin/upgradeprovision | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index e58a2647b6..9d3b683940 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -905,7 +905,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): cursddl = cursd.as_sddl(names.domainsid) refsd = ndr_unpack(security.descriptor, str(reference[0]["nTSecurityDescriptor"])) - refsddl = cursd.as_sddl(names.domainsid) + refsddl = refsd.as_sddl(names.domainsid) if get_diff_sddls(refsddl, cursddl) == "": message(CHANGE, "sd are identical") -- cgit From 5db07d2f42e6bbc0023a504f30b9dcc8fd31b230 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 5 Jun 2011 17:39:32 +0400 Subject: s4-upgradeprovisision: fix bug 8063, old SD can miss some componenent (group, owner, ...) Don't make the assumption that SD are correct, they can be wrong and misformed. Fix this bug: https://bugzilla.samba.org/show_bug.cgi?id=8063 --- source4/scripting/python/samba/upgradehelpers.py | 36 +++++++++++++----------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 16e4ea006a..ad5de73b5b 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -372,42 +372,46 @@ def get_diff_sddls(refsddl, cursddl): """ txt = "" - hash_new = chunck_sddl(cursddl) + hash_cur = chunck_sddl(cursddl) hash_ref = chunck_sddl(refsddl) - if hash_new["owner"] != hash_ref["owner"]: + if not hash_cur.has_key("owner"): + txt = "\tNo owner in current SD" + elif hash_cur["owner"] != hash_ref["owner"]: txt = "\tOwner mismatch: %s (in ref) %s" \ - "(in current)\n" % (hash_ref["owner"], hash_new["owner"]) + "(in current)\n" % (hash_ref["owner"], hash_cur["owner"]) - if hash_new["group"] != hash_ref["group"]: + if not hash_cur.has_key("group"): + txt = "%s\tNo group in current SD" % txt + elif hash_cur["group"] != hash_ref["group"]: txt = "%s\tGroup mismatch: %s (in ref) %s" \ - "(in current)\n" % (txt, hash_ref["group"], hash_new["group"]) + "(in current)\n" % (txt, hash_ref["group"], hash_cur["group"]) for part in ["dacl", "sacl"]: - if hash_new.has_key(part) and hash_ref.has_key(part): + if hash_cur.has_key(part) and hash_ref.has_key(part): # both are present, check if they contain the same ACE - h_new = set() + h_cur = set() h_ref = set() - c_new = chunck_acl(hash_new[part]) + c_cur = chunck_acl(hash_cur[part]) c_ref = chunck_acl(hash_ref[part]) - for elem in c_new["aces"]: - h_new.add(elem) + for elem in c_cur["aces"]: + h_cur.add(elem) for elem in c_ref["aces"]: h_ref.add(elem) for k in set(h_ref): - if k in h_new: - h_new.remove(k) + if k in h_cur: + h_cur.remove(k) h_ref.remove(k) - if len(h_new) + len(h_ref) > 0: + if len(h_cur) + len(h_ref) > 0: txt = "%s\tPart %s is different between reference" \ " and current here is the detail:\n" % (txt, part) - for item in h_new: + for item in h_cur: txt = "%s\t\t%s ACE is not present in the" \ " reference\n" % (txt, item) @@ -415,9 +419,9 @@ def get_diff_sddls(refsddl, cursddl): txt = "%s\t\t%s ACE is not present in the" \ " current\n" % (txt, item) - elif hash_new.has_key(part) and not hash_ref.has_key(part): + elif hash_cur.has_key(part) and not hash_ref.has_key(part): txt = "%s\tReference ACL hasn't a %s part\n" % (txt, part) - elif not hash_new.has_key(part) and hash_ref.has_key(part): + elif not hash_cur.has_key(part) and hash_ref.has_key(part): txt = "%s\tCurrent ACL hasn't a %s part\n" % (txt, part) return txt -- cgit From 45df4d81ed37f6d470e3f42a310a6e5f0afa06bf Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 16:09:14 +0400 Subject: s4-python: fix wrong discovery of the site name in find_key_provision_parameters --- source4/scripting/python/samba/provision/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index f272872a93..0d39befc26 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -266,7 +266,7 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp) names.domaindn=current[0]["defaultNamingContext"] names.rootdn=current[0]["rootDomainNamingContext"] # default site name - res3 = samdb.search(expression="(objectClass=*)", + res3 = samdb.search(expression="(objectClass=site)", base="CN=Sites," + configdn, scope=ldb.SCOPE_ONELEVEL, attrs=["cn"]) names.sitename = str(res3[0]["cn"]) -- cgit From 0065742909453f85709635aa44787b6998cccfc3 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 17:13:26 +0400 Subject: s4-upgradeprovision: handle_special_attributes don't really need ranges of USNs, just the information if we are using replPropertyMetadata for attribute selection --- source4/scripting/bin/upgradeprovision | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 9d3b683940..c625625c44 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -297,7 +297,7 @@ def print_provision_key_parameters(names): message(GUESS, "domainlevel :" + str(names.domainlevel)) -def handle_special_case(att, delta, new, old, usn, basedn, aldb): +def handle_special_case(att, delta, new, old, useReplMetadata, basedn, aldb): """Define more complicate update rules for some attributes :param att: The attribute to be updated @@ -305,7 +305,8 @@ def handle_special_case(att, delta, new, old, usn, basedn, aldb): between the updated object and the reference one :param new: The reference object :param old: The Updated object - :param usn: The highest usn modified by a previous (upgrade)provision + :param useReplMetadata: A boolean that indicate if the update process + use replPropertyMetaData to decide what has to be updated. :param basedn: The base DN of the provision :param aldb: An ldb object used to build DN :return: True to indicate that the attribute should be kept, False for @@ -315,7 +316,7 @@ def handle_special_case(att, delta, new, old, usn, basedn, aldb): # We do most of the special case handle if we do not have the # highest usn as otherwise the replPropertyMetaData will guide us more # correctly - if usn is None: + if not useReplMetadata: if (att == "sPNMappings" and flag == FLAG_MOD_REPLACE and ldb.Dn(aldb, "CN=Directory Service,CN=Windows NT," "CN=Services,CN=Configuration,%s" % basedn) @@ -889,7 +890,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): # idea to change it delta.remove(att) continue - if handle_special_case(att, delta, reference, current, usns, basedn, samdb): + if handle_special_case(att, delta, reference, current, True, basedn, samdb): # This attribute is "complicated" to handle and handling # was done in handle_special_case continue @@ -959,7 +960,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if not hashOverwrittenAtt.has_key(att): if msgElt.flags() != FLAG_MOD_ADD: if not handle_special_case(att, delta, reference, current, - usns, basedn, samdb): + False, basedn, samdb): if opts.debugchange or opts.debugall: try: dump_denied_change(dn, att, -- cgit From d9abcc93847fedf3ca272fe69cde0a92e76c85d0 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 17:50:00 +0400 Subject: s4-upgradeprovision: split update_present in two functions depending on the method used In order to make the function a bit more clearer and with less depth, the selection of attribute that are not updated is split in two functions depending on the fact that we are using mainly replPropertyMetadata to make our choice or if we are using the list of attributes that should, could or shouldn't be updated/created/deleted. --- source4/scripting/bin/upgradeprovision | 301 +++++++++++++++++++-------------- 1 file changed, 171 insertions(+), 130 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index c625625c44..db42543723 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -774,6 +774,167 @@ msg_elt_flag_strs = { ldb.FLAG_MOD_REPLACE: "MOD_REPLACE", ldb.FLAG_MOD_DELETE: "MOD_DELETE" } +def checkKeepAttributeOldMtd(delta, att, reference, current, + basedn, samdb): + """ Check if we should keep the attribute modification or not. + This function didn't use replicationMetadata to take a decision. + + :param delta: A message diff object + :param att: An attribute + :param reference: A message object for the current entry comming from + the reference provision. + :param current: A message object for the current entry commin from + the current provision. + :param basedn: The DN of the partition + :param samdb: A ldb connection to the sam database of the current provision. + + :return: The modified message diff. + """ + # Old school way of handling things for pre alpha12 upgrade + global defSDmodified + isFirst = False + txt = "" + dn = current[0].dn + + for att in list(delta): + defSDmodified = True + msgElt = delta.get(att) + + if att == "nTSecurityDescriptor": + delta.remove(att) + continue + + if att == "dn": + continue + + if not hashOverwrittenAtt.has_key(att): + if msgElt.flags() != FLAG_MOD_ADD: + if not handle_special_case(att, delta, reference, current, + False, basedn, samdb): + if opts.debugchange or opts.debugall: + try: + dump_denied_change(dn, att, + msg_elt_flag_strs[msgElt.flags()], + current[0][att], reference[0][att]) + except KeyError: + dump_denied_change(dn, att, + msg_elt_flag_strs[msgElt.flags()], + current[0][att], None) + delta.remove(att) + continue + else: + if hashOverwrittenAtt.get(att)&2**msgElt.flags() : + continue + elif hashOverwrittenAtt.get(att)==never: + delta.remove(att) + continue + + return delta + +def checkKeepAttributeWithMetadata(delta, att, message, reference, current, + hash_attr_usn, basedn, usns, samdb): + """ Check if we should keep the attribute modification or not + + :param delta: A message diff object + :param att: An attribute + :param message: A function to print messages + :param reference: A message object for the current entry comming from + the reference provision. + :param current: A message object for the current entry commin from + the current provision. + :param hash_attr_usn: A dictionnary with attribute name as keys, + USN and invocation id as values. + :param basedn: The DN of the partition + :param usns: A dictionnary with invocation ID as keys and USN ranges + as values. + :param samdb: A ldb object pointing to the sam DB + + :return: The modified message diff. + """ + global defSDmodified + isFirst = False + txt = "" + dn = current[0].dn + + for att in list(delta): + # We have updated by provision usn information so let's exploit + # replMetadataProperties + if att in forwardlinked: + curval = current[0].get(att, ()) + refval = reference[0].get(att, ()) + handle_links(samdb, att, basedn, current[0]["dn"], + curval, refval, delta) + continue + + if isFirst and len(delta.items())>1: + isFirst = True + txt = "%s\n" % (str(dn)) + + keptAttr = ["dn", "rIDAvailablePool", "objectSid", "creationTime", "oEMInformation", "msDs-KeyVersionNumber"] + if att in keptAttr: + delta.remove(att) + continue + + if handle_special_case(att, delta, reference, current, True, None, None): + # This attribute is "complicated" to handle and handling + # was done in handle_special_case + continue + + attrUSN = None + if hash_attr_usn.get(att): + attrUSN = hash_attr_usn.get(att) + + if att == "forceLogoff" and attrUSN is None: + continue + if attrUSN is None: + delta.remove(att) + continue + if att == "nTSecurityDescriptor": + cursd = ndr_unpack(security.descriptor, + str(current[0]["nTSecurityDescriptor"])) + cursddl = cursd.as_sddl(names.domainsid) + refsd = ndr_unpack(security.descriptor, + str(reference[0]["nTSecurityDescriptor"])) + refsddl = refsd.as_sddl(names.domainsid) + + if get_diff_sddls(refsddl, cursddl) == "": + message(CHANGE, "sd are identical") + else: + message(CHANGE, "sd are not identical") + if attrUSN == -1: + # This attribute was last modified by another DC forget + # about it + message(CHANGE, "%sAttribute: %s has been " + "created/modified/deleted by another DC. " + "Doing nothing" % (txt, att)) + txt = "" + delta.remove(att) + continue + elif not usn_in_range(int(attrUSN), usns.get(attInvId)): + message(CHANGE, "%sAttribute: %s was not " + "created/modified/deleted during a " + "provision or upgradeprovision. Current " + "usn: %d. Doing nothing" % (txt, att, + attrUSN)) + txt = "" + delta.remove(att) + continue + else: + if att == "defaultSecurityDescriptor": + defSDmodified = True + if attrUSN: + message(CHANGE, "%sAttribute: %s will be modified" + "/deleted it was last modified " + "during a provision. Current usn: " + "%d" % (txt, att, attrUSN)) + txt = "" + else: + message(CHANGE, "%sAttribute: %s will be added because " + "it did not exist before" % (txt, att)) + txt = "" + continue + + return delta def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): """ This function updates the object that are already present in the @@ -788,7 +949,6 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): upgradeprovision :param invocationid: The value of the invocationid for the current DC""" - global defSDmodified # This hash is meant to speedup lookup of attribute name from an oid, # it's for the replPropertyMetaData handling hash_oid_name = {} @@ -805,6 +965,8 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): changed = 0 controls = ["search_options:1:2", "sd_flags:1:2"] + if usns is not None: + message(CHANGE, "Using replPropertyMetadata for change selection") for dn in listPresent: reference = ref_samdb.search(expression="dn=%s" % (str(dn)), base=basedn, scope=SCOPE_SUBTREE, @@ -826,9 +988,6 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): delta = samdb.msg_diff(current[0], reference[0]) - for att in hashAttrNotCopied.keys(): - delta.remove(att) - for att in backlinked: delta.remove(att) @@ -851,133 +1010,15 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): # Note we could just use 1 here hash_attr_usn[att] = o.originating_usn else: - hash_attr_usn[att] = -1 - - isFirst = 0 - txt = "" - - for att in list(delta): - if usns is not None: - # We have updated by provision usn information so let's exploit - # replMetadataProperties - if att in forwardlinked: - curval = current[0].get(att, ()) - refval = reference[0].get(att, ()) - handle_links(samdb, att, basedn, current[0]["dn"], - curval, refval, delta) - continue - - if isFirst == 0 and len(delta.items())>1: - isFirst = 1 - txt = "%s\n" % (str(dn)) - if att == "dn": - # There is always a dn attribute after a msg_diff - continue - if att == "rIDAvailablePool": - delta.remove(att) - continue - if att == "objectSid": - delta.remove(att) - continue - if att == "creationTime": - delta.remove(att) - continue - if att == "oEMInformation": - delta.remove(att) - continue - if att == "msDs-KeyVersionNumber": - # This is the kvno of the computer/user it's a very bad - # idea to change it - delta.remove(att) - continue - if handle_special_case(att, delta, reference, current, True, basedn, samdb): - # This attribute is "complicated" to handle and handling - # was done in handle_special_case - continue - attrUSN = hash_attr_usn.get(att) - if att == "forceLogoff" and attrUSN is None: - continue - if attrUSN is None: - delta.remove(att) - continue - if att == "nTSecurityDescriptor": - cursd = ndr_unpack(security.descriptor, - str(current[0]["nTSecurityDescriptor"])) - cursddl = cursd.as_sddl(names.domainsid) - refsd = ndr_unpack(security.descriptor, - str(reference[0]["nTSecurityDescriptor"])) - refsddl = refsd.as_sddl(names.domainsid) - - if get_diff_sddls(refsddl, cursddl) == "": - message(CHANGE, "sd are identical") - else: - message(CHANGE, "sd are not identical") - if attrUSN == -1: - # This attribute was last modified by another DC forget - # about it - message(CHANGE, "%sAttribute: %s has been " - "created/modified/deleted by another DC. " - "Doing nothing" % (txt, att)) - txt = "" - delta.remove(att) - continue - elif not usn_in_range(int(attrUSN), usns): - message(CHANGE, "%sAttribute: %s was not " - "created/modified/deleted during a " - "provision or upgradeprovision. Current " - "usn: %d. Doing nothing" % (txt, att, - attrUSN)) - txt = "" - delta.remove(att) - continue - else: - if att == "defaultSecurityDescriptor": - defSDmodified = True - if attrUSN: - message(CHANGE, "%sAttribute: %s will be modified" - "/deleted it was last modified " - "during a provision. Current usn: " - "%d" % (txt, att, attrUSN)) - txt = "" - else: - message(CHANGE, "%sAttribute: %s will be added because " - "it did not exist before" % (txt, att)) - txt = "" - continue - - else: - # Old school way of handling things for pre alpha12 upgrade - defSDmodified = True - msgElt = delta.get(att) - if att == "nTSecurityDescriptor": - delta.remove(att) - continue - - if att == "dn": - continue - - if not hashOverwrittenAtt.has_key(att): - if msgElt.flags() != FLAG_MOD_ADD: - if not handle_special_case(att, delta, reference, current, - False, basedn, samdb): - if opts.debugchange or opts.debugall: - try: - dump_denied_change(dn, att, - msg_elt_flag_strs[msgElt.flags()], - current[0][att], reference[0][att]) - except KeyError: - dump_denied_change(dn, att, - msg_elt_flag_strs[msgElt.flags()], - current[0][att], None) - delta.remove(att) - continue - else: - if hashOverwrittenAtt.get(att)&2**msgElt.flags() : - continue - elif hashOverwrittenAtt.get(att)==never: - delta.remove(att) - continue + if usns is not None: + delta = checkKeepAttributeWithMetadata(delta, att, message, reference, + current, hash_attr_usn, + basedn, usns, samdb) + else: + for att in hashAttrNotCopied.keys(): + delta.remove(att) + delta = checkKeepAttributeOldMtd(delta, att, reference, current, basedn, samdb) delta.dn = dn if len(delta.items()) >1: -- cgit From 71ab462c81b48169b34d60dd2bbeca137a15b702 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 18:34:49 +0400 Subject: s4-upgradeprovision: add function to know if attribute is replicated or not --- source4/scripting/bin/upgradeprovision | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index db42543723..a9dffc0ab5 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -117,6 +117,7 @@ hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace, backlinked = [] forwardlinked = set() dn_syntax_att = [] +not_replicated = [] def define_what_to_log(opts): what = 0 if opts.debugchange: @@ -238,6 +239,25 @@ def populate_links(samdb, schemadn): for t in linkedAttHash.keys(): forwardlinked.add(t) +def isReplicated(att): + """ Indicate if the attribute is replicated or not + + :param att: Name of the attribute to be tested + :return: True is the attribute is replicated, False otherwise + """ + + return (att not in not_replicated) + +def populateNotReplicated(samdb, schemadn): + """Populate an array with all the attributes that are not replicated + + :param samdb: A LDB object for sam.ldb file + :param schemadn: DN of the schema for the partition""" + res = samdb.search(expression="(&(objectclass=attributeSchema)(systemflags:1.2.840.113556.1.4.803:=1))", base=Dn(samdb, + str(schemadn)), scope=SCOPE_SUBTREE, + attrs=["lDAPDisplayName"]) + for elem in res: + not_replicated.append(elem["lDAPDisplayName"]) def populate_dnsyntax(samdb, schemadn): """Populate an array with all the attributes that have DN synthax -- cgit From 20233cdf535b55ee3832d4844eb2109cccab5837 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 17:39:06 +0400 Subject: s4-upgradeprovision: introduce invocation id in lastprovisionUSNs --- source4/scripting/bin/upgradeprovision | 46 +++++++++++++----- .../scripting/python/samba/provision/__init__.py | 56 +++++++++++++++------- 2 files changed, 73 insertions(+), 29 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index a9dffc0ab5..7f11e404ab 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -902,10 +902,22 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, attrUSN = None if hash_attr_usn.get(att): - attrUSN = hash_attr_usn.get(att) + [attrUSN, attInvId] = hash_attr_usn.get(att) + + if attrUSN is None: + # If it's a replicated attribute and we don't have any USN + # information about it. It means that we never saw it before + # so let's add it ! + # If it is a replicated attribute but we are not master on it + # (ie. not initially added in the provision we masterize). + # attrUSN will be -1 + if isReplicated(att): + continue + elif att in hashAttrNotCopied.keys(): + delta.remove(att) + else: + continue - if att == "forceLogoff" and attrUSN is None: - continue if attrUSN is None: delta.remove(att) continue @@ -956,7 +968,7 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, return delta -def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): +def update_present(ref_samdb, samdb, basedn, listPresent, usns): """ This function updates the object that are already present in the provision @@ -966,8 +978,8 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): (ie. DC=foo, DC=bar) :param listPresent: A list of object that is present in the provision :param usns: A list of USN range modified by previous provision and - upgradeprovision - :param invocationid: The value of the invocationid for the current DC""" + upgradeprovision grouped by invocation ID + """ # This hash is meant to speedup lookup of attribute name from an oid, # it's for the replPropertyMetaData handling @@ -1026,10 +1038,10 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): # We put in this hash only modification # made on the current host att = hash_oid_name[samdb.get_oid_from_attid(o.attid)] - if str(o.originating_invocation_id) == str(invocationid): - # Note we could just use 1 here - hash_attr_usn[att] = o.originating_usn + if str(o.originating_invocation_id) in usns.keys(): + hash_attr_usn[att] = [o.originating_usn, str(o.originating_invocation_id)] else: + hash_attr_usn[att] = [-1, None] if usns is not None: delta = checkKeepAttributeWithMetadata(delta, att, message, reference, @@ -1160,7 +1172,7 @@ def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs, pre message(SIMPLE, "Schema reloaded!") changed = update_present(ref_samdb, samdb, basedn, listPresent, - provisionUSNs, names.invocation) + provisionUSNs) message(SIMPLE, "There are %d changed objects" % (changed)) return 1 @@ -1665,9 +1677,19 @@ if __name__ == '__main__': # 4) lastProvisionUSNs = get_last_provision_usn(ldbs.sam) if lastProvisionUSNs is not None: + v = 0 + for k in lastProvisionUSNs.keys(): + for r in lastProvisionUSNs[k]: + v = v + 1 + message(CHANGE, - "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs)) + "Find last provision USN, %d invocation(s) for a total of %d ranges" % \ + (len(lastProvisionUSNs.keys()), v /2 )) + if lastProvisionUSNs.get("default") != None: + message(CHANGE, "Old style for usn ranges used") + lastProvisionUSNs[str(names.invocation)] = lastProvisionUSNs["default"] + del lastProvisionUSNs["default"] # Objects will be created with the admin session # (not anymore system session) adm_session = admin_session(lp, str(names.domainsid)) @@ -1853,7 +1875,7 @@ if __name__ == '__main__': check_for_DNS(newpaths.private_dir, paths.private_dir) # 22) if lastProvisionUSNs is not None: - update_provision_usn(ldbs.sam, minUSN, maxUSN) + update_provision_usn(ldbs.sam, minUSN, maxUSN, names.invocation) if opts.full and (names.policyid is None or names.policyid_dc is None): update_policyids(names, ldbs.sam) if opts.full or opts.resetfileacl or opts.fixntacl: diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index 0d39befc26..7c9f223d11 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -322,7 +322,7 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp) raise ProvisioningError("Unable to find uid/gid for Domain Admins rid") return names -def update_provision_usn(samdb, low, high, replace=False): +def update_provision_usn(samdb, low, high, id, replace=False): """Update the field provisionUSN in sam.ldb This field is used to track range of USN modified by provision and @@ -333,6 +333,7 @@ def update_provision_usn(samdb, low, high, replace=False): :param samdb: An LDB object connect to sam.ldb :param low: The lowest USN modified by this upgrade :param high: The highest USN modified by this upgrade + :param id: The invocation id of the samba's dc :param replace: A boolean indicating if the range should replace any existing one or appended (default) """ @@ -344,17 +345,24 @@ def update_provision_usn(samdb, low, high, replace=False): scope=ldb.SCOPE_SUBTREE, attrs=[LAST_PROVISION_USN_ATTRIBUTE, "dn"]) for e in entry[0][LAST_PROVISION_USN_ATTRIBUTE]: + if not re.search(';', e): + e = "%s;%s" % (e, id) tab.append(str(e)) - tab.append("%s-%s" % (low, high)) + tab.append("%s-%s;%s" % (low, high, id)) delta = ldb.Message() delta.dn = ldb.Dn(samdb, "@PROVISION") delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab, ldb.FLAG_MOD_REPLACE, LAST_PROVISION_USN_ATTRIBUTE) + entry = samdb.search(expression="(&(dn=@PROVISION)(provisionnerID=*))", + base="", scope=ldb.SCOPE_SUBTREE, + attrs=["provisionnerID"]) + if len(entry) == 0 or len(entry[0]) == 0: + delta["provisionnerID"] = ldb.MessageElement(id, ldb.FLAG_MOD_ADD, "provisionnerID") samdb.modify(delta) -def set_provision_usn(samdb, low, high): +def set_provision_usn(samdb, low, high, id): """Set the field provisionUSN in sam.ldb This field is used to track range of USN modified by provision and upgradeprovision. @@ -363,9 +371,12 @@ def set_provision_usn(samdb, low, high): :param samdb: An LDB object connect to sam.ldb :param low: The lowest USN modified by this upgrade - :param high: The highest USN modified by this upgrade""" + :param high: The highest USN modified by this upgrade + :param id: The invocationId of the provision""" + tab = [] - tab.append("%s-%s" % (low, high)) + tab.append("%s-%s;%s" % (low, high, id)) + delta = ldb.Message() delta.dn = ldb.Dn(samdb, "@PROVISION") delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab, @@ -390,25 +401,36 @@ def get_max_usn(samdb,basedn): def get_last_provision_usn(sam): - """Get the lastest USN modified by a provision or an upgradeprovision + """Get USNs ranges modified by a provision or an upgradeprovision :param sam: An LDB object pointing to the sam.ldb - :return: an integer corresponding to the highest USN modified by - (upgrade)provision, 0 is this value is unknown + :return: a dictionnary which keys are invocation id and values are an array + of integer representing the different ranges """ entry = sam.search(expression="(&(dn=@PROVISION)(%s=*))" % LAST_PROVISION_USN_ATTRIBUTE, base="", scope=ldb.SCOPE_SUBTREE, - attrs=[LAST_PROVISION_USN_ATTRIBUTE]) + attrs=[LAST_PROVISION_USN_ATTRIBUTE, "provisionnerID"]) if len(entry): - range = [] - idx = 0 + myids = [] + range = {} p = re.compile(r'-') + if entry[0].get("provisionnerID"): + for e in entry[0]["provisionnerID"]: + myids.append(str(e)) for r in entry[0][LAST_PROVISION_USN_ATTRIBUTE]: - tab = p.split(str(r)) - range.append(tab[0]) - range.append(tab[1]) - idx = idx + 1 + tab1 = str(r).split(';') + if len(tab1) == 2: + id = tab1[1] + else: + id = "default" + if (len(myids) > 0 and id not in myids): + continue + tab2 = p.split(tab1[0]) + if range.get(id) == None: + range[id] = [] + range[id].append(tab2[0]) + range[id].append(tab2[1]) return range else: return None @@ -1780,9 +1802,9 @@ def provision(logger, session_info, credentials, smbconf=None, lastProvisionUSNs = get_last_provision_usn(samdb) maxUSN = get_max_usn(samdb, str(names.rootdn)) if lastProvisionUSNs is not None: - update_provision_usn(samdb, 0, maxUSN, 1) + update_provision_usn(samdb, 0, maxUSN, invocationid, 1) else: - set_provision_usn(samdb, 0, maxUSN) + set_provision_usn(samdb, 0, maxUSN, invocationid) create_krb5_conf(paths.krb5conf, dnsdomain=names.dnsdomain, hostname=names.hostname, -- cgit From 9a18e07b4f186751cb25dfc0f947e6e5ca8f2fee Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 17:56:17 +0400 Subject: s4-upgradeprovision: clean up, reformating and update docs --- source4/scripting/bin/upgradeprovision | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 7f11e404ab..85f21678d6 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -412,14 +412,14 @@ def handle_special_case(att, delta, new, old, useReplMetadata, basedn, aldb): if (att == "servicePrincipalName" and flag == FLAG_MOD_REPLACE): hash = {} newval = [] - changeDelta=0 + changeDelta = 0 for elem in old[0][att]: hash[str(elem)]=1 newval.append(str(elem)) for elem in new[0][att]: if not hash.has_key(str(elem)): - changeDelta=1 + changeDelta = 1 newval.append(str(elem)) if changeDelta == 1: delta[att] = MessageElement(newval, FLAG_MOD_REPLACE, att) @@ -1109,8 +1109,8 @@ def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs, pre :param basedn: String value of the DN of the partition :param names: List of key provision parameters :param schema: A Schema object - :param provisionUSNs: The USNs modified by provision/upgradeprovision - last time + :param provisionUSNs: A dictionnary with range of USN modified during provision + or upgradeprovision. Ranges are grouped by invocationID. :param prereloadfunc: A function that must be executed just before the reload of the schema """ @@ -1309,7 +1309,6 @@ def removeProvisionUSN(samdb): attrs = [samba.provision.LAST_PROVISION_USN_ATTRIBUTE, "dn"] entry = samdb.search(expression="dn=@PROVISION", base = "", scope=SCOPE_SUBTREE, - controls=["search_options:1:2"], attrs=attrs) empty = Message() empty.dn = entry[0].dn @@ -1379,7 +1378,7 @@ def update_privilege(ref_private_path, cur_private_path): os.path.join(cur_private_path, "privilege.ldb")) -def update_samdb(ref_samdb, samdb, names, highestUSN, schema, prereloadfunc): +def update_samdb(ref_samdb, samdb, names, provisionUSNs, schema, prereloadfunc): """Upgrade the SAM DB contents for all the provision partitions :param ref_sambdb: An LDB object conntected to the sam.ldb of the reference @@ -1387,8 +1386,8 @@ def update_samdb(ref_samdb, samdb, names, highestUSN, schema, prereloadfunc): :param samdb: An LDB object connected to the sam.ldb of the update provision :param names: List of key provision parameters - :param highestUSN: The highest USN modified by provision/upgradeprovision - last time + :param provisionUSNs: A dictionnary with range of USN modified during provision + or upgradeprovision. Ranges are grouped by invocationID. :param schema: A Schema object that represent the schema of the provision :param prereloadfunc: A function that must be executed just before the reload of the schema @@ -1396,7 +1395,7 @@ def update_samdb(ref_samdb, samdb, names, highestUSN, schema, prereloadfunc): message(SIMPLE, "Starting update of samdb") ret = update_partition(ref_samdb, samdb, str(names.rootdn), names, - schema, highestUSN, prereloadfunc) + schema, provisionUSNs, prereloadfunc) if ret: message(SIMPLE, "Update of samdb finished") return 1 -- cgit From 44c540625216b7f9754f7e9461bbd5d026a1e9cf Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 17:15:37 +0400 Subject: s4-upgradeprovision: don't print dn in the list of modified attributes --- source4/scripting/bin/upgradeprovision | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 85f21678d6..b197c6cb84 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -1054,7 +1054,8 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns): delta.dn = dn if len(delta.items()) >1: - attributes=", ".join(delta.keys()) + # Skip dn as the value is not really changed ... + attributes=", ".join(delta.keys()[1:]) modcontrols = [] relaxedatt = ['iscriticalsystemobject', 'grouptype'] # Let's try to reduce as much as possible the use of relax control -- cgit From 01758595e3c01751f259e5b2edaf07beb982ed76 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 18:37:51 +0400 Subject: s4-upgradeprovision: remove useless code --- source4/scripting/bin/upgradeprovision | 3 --- 1 file changed, 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index b197c6cb84..735757aa2c 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -918,9 +918,6 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, else: continue - if attrUSN is None: - delta.remove(att) - continue if att == "nTSecurityDescriptor": cursd = ndr_unpack(security.descriptor, str(current[0]["nTSecurityDescriptor"])) -- cgit From 4305f54b8ef9fdcc1ca075b991e9dadab4b485c7 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 00:02:03 +0400 Subject: s4-upgradeprovision: fix inverted logic and wrong flags on sd_flags control --- source4/scripting/bin/upgradeprovision | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 735757aa2c..b49ccf91c0 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -872,7 +872,7 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, :return: The modified message diff. """ global defSDmodified - isFirst = False + isFirst = True txt = "" dn = current[0].dn @@ -887,7 +887,7 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, continue if isFirst and len(delta.items())>1: - isFirst = True + isFirst = False txt = "%s\n" % (str(dn)) keptAttr = ["dn", "rIDAvailablePool", "objectSid", "creationTime", "oEMInformation", "msDs-KeyVersionNumber"] @@ -930,6 +930,7 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, message(CHANGE, "sd are identical") else: message(CHANGE, "sd are not identical") + if attrUSN == -1: # This attribute was last modified by another DC forget # about it @@ -993,7 +994,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns): raise ProvisioningError(msg) changed = 0 - controls = ["search_options:1:2", "sd_flags:1:2"] + controls = ["search_options:1:2", "sd_flags:1:0"] if usns is not None: message(CHANGE, "Using replPropertyMetadata for change selection") for dn in listPresent: -- cgit From f76c206e2fd9af47767816e6b284e3742672b21a Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 18:49:23 +0400 Subject: s4-upgradeprovision: change hashAttrNotCopied to be an array --- source4/scripting/bin/upgradeprovision | 48 ++++++++++++++++------------------ 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index b49ccf91c0..c353fe0749 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -81,20 +81,21 @@ __docformat__ = "restructuredText" # This is most probably because they are populated automatcally when object is # created # This also apply to imported object from reference provision -hashAttrNotCopied = { "dn": 1, "whenCreated": 1, "whenChanged": 1, - "objectGUID": 1, "uSNCreated": 1, - "replPropertyMetaData": 1, "uSNChanged": 1, - "parentGUID": 1, "objectCategory": 1, - "distinguishedName": 1, "nTMixedDomain": 1, - "showInAdvancedViewOnly": 1, "instanceType": 1, - "msDS-Behavior-Version":1, "nextRid":1, "cn": 1, - "lmPwdHistory":1, "pwdLastSet": 1, - "ntPwdHistory":1, "unicodePwd":1,"dBCSPwd":1, - "supplementalCredentials":1, "gPCUserExtensionNames":1, - "gPCMachineExtensionNames":1,"maxPwdAge":1, "secret":1, - "possibleInferiors":1, "privilege":1, - "sAMAccountType":1 } - +replAttrNotCopied = [ "dn", "whenCreated", "whenChanged", "objectGUID", + "parentGUID", "objectCategory", "distinguishedName", + "nTMixedDomain", "showInAdvancedViewOnly", + "instanceType", "msDS-Behavior-Version", "cn", + "lmPwdHistory", "pwdLastSet", "ntPwdHistory", + "unicodePwd", "dBCSPwd", "supplementalCredentials", + "gPCUserExtensionNames", "gPCMachineExtensionNames", + "maxPwdAge", "secret", "possibleInferiors", "privilege", + "sAMAccountType", "oEMInformation", "creationTime" ] + +nonreplAttrNotCopied = ["uSNCreated", "replPropertyMetaData", "uSNChanged", + "nextRid" ,"rIDNextRID"] + +attrNotCopied = replAttrNotCopied +attrNotCopied.extend(nonreplAttrNotCopied) # Usually for an object that already exists we do not overwrite attributes as # they might have been changed for good reasons. Anyway for a few of them it's # mandatory to replace them otherwise the provision will be broken somehow. @@ -606,7 +607,7 @@ def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index): m = re.match(r".*-(\d+)$", sid) if m and int(m.group(1))>999: delta.remove("objectSid") - for att in hashAttrNotCopied.keys(): + for att in attrNotCopied: delta.remove(att) for att in backlinked: delta.remove(att) @@ -673,7 +674,7 @@ def add_deletedobj_containers(ref_samdb, samdb, names): delta = samdb.msg_diff(empty, reference[0]) delta.dn = Dn(samdb, str(reference[0]["dn"])) - for att in hashAttrNotCopied.keys(): + for att in attrNotCopied: delta.remove(att) modcontrols = ["relax:0", "provision:0"] @@ -890,11 +891,6 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, isFirst = False txt = "%s\n" % (str(dn)) - keptAttr = ["dn", "rIDAvailablePool", "objectSid", "creationTime", "oEMInformation", "msDs-KeyVersionNumber"] - if att in keptAttr: - delta.remove(att) - continue - if handle_special_case(att, delta, reference, current, True, None, None): # This attribute is "complicated" to handle and handling # was done in handle_special_case @@ -913,9 +909,8 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, # attrUSN will be -1 if isReplicated(att): continue - elif att in hashAttrNotCopied.keys(): - delta.remove(att) else: + message(CHANGE, "Non replicated attribute %s changed" % att) continue if att == "nTSecurityDescriptor": @@ -1021,6 +1016,9 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns): for att in backlinked: delta.remove(att) + for att in attrNotCopied: + delta.remove(att) + delta.remove("name") if len(delta.items()) > 1 and usns is not None: @@ -1046,8 +1044,6 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns): current, hash_attr_usn, basedn, usns, samdb) else: - for att in hashAttrNotCopied.keys(): - delta.remove(att) delta = checkKeepAttributeOldMtd(delta, att, reference, current, basedn, samdb) delta.dn = dn @@ -1611,7 +1607,7 @@ def sync_calculated_attributes(samdb, names): # This resulting object is filtered to remove all the back link attribute # (ie. memberOf) as they will be created by the other linked object (ie. # the one with the member attribute) -# All attributes specified in the hashAttrNotCopied associative array are +# All attributes specified in the attrNotCopied array are # also removed it's most of the time generated attributes # After missing entries have been added the update_partition function will -- cgit From 0e729149259055e9310c1dee78fce71a744006ab Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 22:59:35 +0400 Subject: s4-upgradeprovision: dn must be skipped as delta.remove("dn") do not remove this attribute --- source4/scripting/bin/upgradeprovision | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index c353fe0749..79cf97dce4 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -878,6 +878,9 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, dn = current[0].dn for att in list(delta): + if att == "dn": + # dn is not removable + continue # We have updated by provision usn information so let's exploit # replMetadataProperties if att in forwardlinked: -- cgit From 930d2f28c99d5cf8823ca0837a632e13cead9fce Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 13 Jun 2011 23:23:05 +0400 Subject: s4-upgradeprovision: if there is nothing to really modify then skip it --- source4/scripting/bin/upgradeprovision | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 79cf97dce4..b214c4c8fd 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -1024,6 +1024,9 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns): delta.remove("name") + if len(delta.items()) == 1: + continue + if len(delta.items()) > 1 and usns is not None: # Fetch the replPropertyMetaData res = samdb.search(expression="dn=%s" % (str(dn)), base=basedn, -- cgit From f7a903ee8085bb041cae8fdf603997e66245f35f Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 14 Jun 2011 01:39:41 +0400 Subject: s4-upgradeprovision: add a list of attribute that are not DSDB attribute that we don't want to copy --- source4/scripting/bin/upgradeprovision | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index b214c4c8fd..e2d5cb0fb8 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -94,8 +94,12 @@ replAttrNotCopied = [ "dn", "whenCreated", "whenChanged", "objectGUID", nonreplAttrNotCopied = ["uSNCreated", "replPropertyMetaData", "uSNChanged", "nextRid" ,"rIDNextRID"] +nonDSDBAttrNotCopied = ["msDS-KeyVersionNumber", "priorSecret", "priorWhenChanged"] + + attrNotCopied = replAttrNotCopied attrNotCopied.extend(nonreplAttrNotCopied) +attrNotCopied.extend(nonDSDBAttrNotCopied) # Usually for an object that already exists we do not overwrite attributes as # they might have been changed for good reasons. Anyway for a few of them it's # mandatory to replace them otherwise the provision will be broken somehow. -- cgit From bc7b8fa108bf27f78c69f5aec3e408e59555c232 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 14 Jun 2011 01:41:56 +0400 Subject: s4-upgradeprovision: ignore objectSid --- source4/scripting/bin/upgradeprovision | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index e2d5cb0fb8..bf06a3c4f7 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -882,9 +882,10 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, dn = current[0].dn for att in list(delta): - if att == "dn": - # dn is not removable + if att in ["dn", "objectSid"]: + delta.remove(att) continue + # We have updated by provision usn information so let's exploit # replMetadataProperties if att in forwardlinked: -- cgit From c0eb4037585e1feb609d7acef196c4dc8872960b Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 14 Jun 2011 01:42:28 +0400 Subject: s4-upgradeprovision: remove useless comment --- source4/scripting/bin/upgradeprovision | 1 - 1 file changed, 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index bf06a3c4f7..a5a42a9d46 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -1064,7 +1064,6 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns): modcontrols = [] relaxedatt = ['iscriticalsystemobject', 'grouptype'] # Let's try to reduce as much as possible the use of relax control - #for checkedatt in relaxedatt: for attr in delta.keys(): if attr.lower() in relaxedatt: modcontrols = ["relax:0", "provision:0"] -- cgit From 7128345969927461ec281583abec3ea51bf98586 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sat, 18 Jun 2011 23:21:18 +0400 Subject: s4-python: make checks of sacl in get_diff_sddls optionnal --- source4/scripting/python/samba/upgradehelpers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index ad5de73b5b..baba332c23 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -360,7 +360,7 @@ def chunck_sddl(sddl): return hash -def get_diff_sddls(refsddl, cursddl): +def get_diff_sddls(refsddl, cursddl, checkSacl = True): """Get the difference between 2 sddl This function split the textual representation of ACL into smaller @@ -368,6 +368,7 @@ def get_diff_sddls(refsddl, cursddl): :param refsddl: First sddl to compare :param cursddl: Second sddl to compare + :param checkSacl: If false we skip the sacl checks :return: A string that explain difference between sddls """ @@ -387,7 +388,10 @@ def get_diff_sddls(refsddl, cursddl): txt = "%s\tGroup mismatch: %s (in ref) %s" \ "(in current)\n" % (txt, hash_ref["group"], hash_cur["group"]) - for part in ["dacl", "sacl"]: + parts = [ "dacl" ] + if checkSacl: + parts.append("sacl") + for part in parts: if hash_cur.has_key(part) and hash_ref.has_key(part): # both are present, check if they contain the same ACE -- cgit From 5e81ee8b341c3c6a6f9a321ec6ddf9b29932b683 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 14 Jun 2011 01:42:59 +0400 Subject: s4-upgradeprovision: Rework completly how SDs are recalculated --- source4/scripting/bin/upgradeprovision | 165 ++++++++++++++++++++------------- 1 file changed, 99 insertions(+), 66 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index a5a42a9d46..284b0e0ef8 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -42,7 +42,7 @@ from samba.credentials import DONT_USE_KERBEROS from samba.auth import system_session, admin_session from ldb import (SCOPE_SUBTREE, SCOPE_BASE, FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE, - MessageElement, Message, Dn) + MessageElement, Message, Dn, LdbError) from samba import param, dsdb, Ldb from samba.provision import (get_domain_descriptor, find_provision_key_parameters, get_config_descriptor, @@ -119,6 +119,8 @@ hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace, "attributeDisplayNames": replace + add, "versionNumber": add} +dnNotToRecalculate = [] +dnToRecalculate = [] backlinked = [] forwardlinked = set() dn_syntax_att = [] @@ -822,10 +824,10 @@ def checkKeepAttributeOldMtd(delta, att, reference, current, dn = current[0].dn for att in list(delta): - defSDmodified = True msgElt = delta.get(att) if att == "nTSecurityDescriptor": + defSDmodified = True delta.remove(att) continue @@ -929,10 +931,25 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current, str(reference[0]["nTSecurityDescriptor"])) refsddl = refsd.as_sddl(names.domainsid) - if get_diff_sddls(refsddl, cursddl) == "": - message(CHANGE, "sd are identical") + diff = get_diff_sddls(refsddl, cursddl) + if diff == "": + # FIXME find a way to have it only with huge huge verbose mode + # message(CHANGE, "%ssd are identical" % txt) + # txt = "" + delta.remove(att) + continue else: - message(CHANGE, "sd are not identical") + delta.remove(att) + message(CHANGESD, "%ssd are not identical:\n%s" % (txt, diff)) + txt = "" + if attrUSN == -1: + message(CHANGESD, "But the SD has been changed by someonelse "\ + "so it's impossible to know if the difference"\ + " cames from the modification or from a previous bug") + dnNotToRecalculate.append(str(dn)) + else: + dnToRecalculate.append(str(dn)) + continue if attrUSN == -1: # This attribute was last modified by another DC forget @@ -1219,7 +1236,7 @@ def check_updated_sd(ref_sam, cur_sam, names): str(current[i]["nTSecurityDescriptor"])) sddl = cursd.as_sddl(names.domainsid) if sddl != hash[key]: - txt = get_diff_sddls(hash[key], sddl) + txt = get_diff_sddls(hash[key], sddl, False) if txt != "": message(CHANGESD, "On object %s ACL is different" " \n%s" % (current[i]["dn"], txt)) @@ -1233,37 +1250,38 @@ def fix_partition_sd(samdb, names): :param samdb: An LDB object pointing to the sam of the current provision :param names: A list of key provision parameters """ + alwaysRecalculate = False + if len(dnToRecalculate) == 0 and len(dnNotToRecalculate) == 0: + alwaysRecalculate = True + + + # NC's DN can't be both in dnToRecalculate and dnNotToRecalculate # First update the SD for the rootdn - res = samdb.search(expression="objectClass=*", base=str(names.rootdn), - scope=SCOPE_BASE, attrs=["dn", "whenCreated"], - controls=["search_options:1:2"]) - delta = Message() - delta.dn = Dn(samdb, str(res[0]["dn"])) - descr = get_domain_descriptor(names.domainsid) - delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE, - "nTSecurityDescriptor") - samdb.modify(delta) + if alwaysRecalculate or str(names.rootdn) in dnToRecalculate: + delta = Message() + delta.dn = Dn(samdb, str(names.rootdn)) + descr = get_domain_descriptor(names.domainsid) + delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE, + "nTSecurityDescriptor") + samdb.modify(delta) + # Then the config dn - res = samdb.search(expression="objectClass=*", base=str(names.configdn), - scope=SCOPE_BASE, attrs=["dn", "whenCreated"], - controls=["search_options:1:2"]) - delta = Message() - delta.dn = Dn(samdb, str(res[0]["dn"])) - descr = get_config_descriptor(names.domainsid) - delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE, - "nTSecurityDescriptor" ) - samdb.modify(delta) - # Then the schema dn - res = samdb.search(expression="objectClass=*", base=str(names.schemadn), - scope=SCOPE_BASE, attrs=["dn", "whenCreated"], - controls=["search_options:1:2"]) + if alwaysRecalculate or str(names.configdn) in dnToRecalculate: + delta = Message() + delta.dn = Dn(samdb, str(names.configdn)) + descr = get_config_descriptor(names.domainsid) + delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE, + "nTSecurityDescriptor" ) + samdb.modify(delta) - delta = Message() - delta.dn = Dn(samdb, str(res[0]["dn"])) - descr = get_schema_descriptor(names.domainsid) - delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE, - "nTSecurityDescriptor" ) - samdb.modify(delta) + # Then the schema dn + if alwaysRecalculate or str(names.schemadn) in dnToRecalculate: + delta = Message() + delta.dn = Dn(samdb, str(names.schemadn)) + descr = get_schema_descriptor(names.domainsid) + delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE, + "nTSecurityDescriptor" ) + samdb.modify(delta) def rebuild_sd(samdb, names): """Rebuild security descriptor of the current provision from scratch @@ -1276,30 +1294,46 @@ def rebuild_sd(samdb, names): :param names: List of key provision parameters""" + fix_partition_sd(samdb, names) + # List of namming contexts + listNC = [str(names.rootdn), str(names.configdn), str(names.schemadn)] hash = {} - res = samdb.search(expression="objectClass=*", base=str(names.rootdn), + if len(dnToRecalculate) == 0: + res = samdb.search(expression="objectClass=*", base=str(names.rootdn), scope=SCOPE_SUBTREE, attrs=["dn", "whenCreated"], controls=["search_options:1:2"]) - for obj in res: - if not (str(obj["dn"]) == str(names.rootdn) or - str(obj["dn"]) == str(names.configdn) or - str(obj["dn"]) == str(names.schemadn)): - hash[str(obj["dn"])] = obj["whenCreated"] - - listkeys = hash.keys() - listkeys.sort(dn_sort) - - for key in listkeys: + for obj in res: + hash[str(obj["dn"])] = obj["whenCreated"] + else: + for dn in dnToRecalculate: + if hash.has_key(dn): + continue + # fetch each dn to recalculate and their child within the same partition + res = samdb.search(expression="objectClass=*", base=dn, + scope=SCOPE_SUBTREE, attrs=["dn", "whenCreated"]) + for obj in res: + hash[str(obj["dn"])] = obj["whenCreated"] + + listKeys = list(set(hash.keys())) + listKeys.sort(dn_sort) + + if len(dnToRecalculate) != 0: + message(CHANGESD, "%d DNs have been marked as needed to be recalculated"\ + ", recalculating %d due to inheritance" + % (len(dnToRecalculate), len(listKeys))) + + for key in listKeys: + if (key in listNC or + key in dnNotToRecalculate): + continue + delta = Message() + delta.dn = Dn(samdb, key) try: - delta = Message() - delta.dn = Dn(samdb, key) delta["whenCreated"] = MessageElement(hash[key], FLAG_MOD_REPLACE, "whenCreated" ) - samdb.modify(delta, ["recalculate_sd:0"]) - except: - # XXX: We should always catch an explicit exception. - # What could go wrong here? + samdb.modify(delta, ["recalculate_sd:0","relax:0"]) + except LdbError, e: samdb.transaction_cancel() res = samdb.search(expression="objectClass=*", base=str(names.rootdn), scope=SCOPE_SUBTREE, @@ -1307,7 +1341,7 @@ def rebuild_sd(samdb, names): controls=["search_options:1:2"]) badsd = ndr_unpack(security.descriptor, str(res[0]["nTSecurityDescriptor"])) - print "bad stuff %s" % badsd.as_sddl(names.domainsid) + message(ERROR, "On %s bad stuff %s" % (str(delta.dn),badsd.as_sddl(names.domainsid))) return def removeProvisionUSN(samdb): @@ -1838,12 +1872,12 @@ if __name__ == '__main__': message(SIMPLE, "Update machine account") update_machine_account_password(ldbs.sam, ldbs.secrets, names) + dnToRecalculate.sort(dn_sort) # 16) SD should be created with admin but as some previous acl were so wrong # that admin can't modify them we have first to recreate them with the good # form but with system account and then give the ownership to admin ... - if not re.match(r'.*alpha(9|\d\d+)', str(oem)): - message(SIMPLE, "Fixing old povision SD") - fix_partition_sd(ldbs.sam, names) + if str(oem) != "" and not re.match(r'.*alpha(9|\d\d+)', str(oem)): + message(SIMPLE, "Fixing very old provision SD") rebuild_sd(ldbs.sam, names) # We calculate the max USN before recalculating the SD because we might @@ -1854,23 +1888,22 @@ if __name__ == '__main__': # 17) maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) - # 18) We rebuild SD only if defaultSecurityDescriptor is modified - # But in fact we should do it also if one object has its SD modified as - # child might need rebuild - if defSDmodified: - message(SIMPLE, "Updating SD") + # 18) We rebuild SD if a we have a list of DN to recalculate or if the + # defSDmodified is set. + if defSDmodified or len(dnToRecalculate) >0: + message(SIMPLE, "Some defaultSecurityDescriptors and/or" + "securityDescriptor have changed, recalculating SD ") ldbs.sam.set_session_info(adm_session) - # Alpha10 was a bit broken still - if re.match(r'.*alpha(\d|10)', str(oem)): - fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) + rebuild_sd(ldbs.sam, names) # 19) # Now we are quite confident in the recalculate process of the SD, we make - # it optional. + # it optional. And we don't do it if there is DN that we must touch + # as we are assured that on this DNs we will have differences ! # Also the check must be done in a clever way as for the moment we just # compare SDDL - if opts.debugchangesd: + if len(dnNotToRecalculate) == 0 and (opts.debugchangesd or opts.debugall): + message(CHANGESD, "Checking recalculated SDs") check_updated_sd(new_ldbs.sam, ldbs.sam, names) # 20) -- cgit From 12b379e9831131c251fde3ebebb76b00323f6bf0 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Wed, 15 Jun 2011 15:20:06 +0400 Subject: s4-upgradeprovision: handle the fact that oEMInformation might not be present --- source4/scripting/python/samba/upgradehelpers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index baba332c23..47ea660e43 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -548,7 +548,7 @@ def getOEMInfo(samdb, rootdn): """ res = samdb.search(expression="(objectClass=*)", base=str(rootdn), scope=SCOPE_BASE, attrs=["dn", "oEMInformation"]) - if len(res) > 0: + if len(res) > 0 and res[0].get("oEMInformation"): info = res[0]["oEMInformation"] return info else: @@ -565,7 +565,10 @@ def updateOEMInfo(samdb, rootdn): res = samdb.search(expression="(objectClass=*)", base=rootdn, scope=SCOPE_BASE, attrs=["dn", "oEMInformation"]) if len(res) > 0: - info = res[0]["oEMInformation"] + if res[0].get("oEMInformation"): + info = str(res[0]["oEMInformation"]) + else: + info = "" info = "%s, upgrade to %s" % (info, version) delta = ldb.Message() delta.dn = ldb.Dn(samdb, str(res[0]["dn"])) -- cgit From 05b2d4147a75a652f8f773d353b62a4c10821155 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Wed, 15 Jun 2011 15:20:46 +0400 Subject: s4-upgradeprovision: deltaattr can be empty or none too --- source4/scripting/bin/upgradeprovision | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 284b0e0ef8..9bf09bd432 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -1808,14 +1808,14 @@ if __name__ == '__main__': doit = True if doit: deltaattr.remove("dn") - for att in deltaattr: - if att.lower() == "dn": - continue - if (deltaattr.get(att) is not None - and deltaattr.get(att).flags() != FLAG_MOD_ADD): - doit = False - elif deltaattr.get(att) is None: - doit = False + for att in deltaattr: + if att.lower() == "dn": + continue + if (deltaattr.get(att) is not None + and deltaattr.get(att).flags() != FLAG_MOD_ADD): + doit = False + elif deltaattr.get(att) is None: + doit = False if doit: message(CHANGE, "Applying delta to @ATTRIBUTES") deltaattr.dn = ldb.Dn(basesam, "@ATTRIBUTES") -- cgit From 15637206b9b51fea31aa267244aeb386c1ba7676 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 00:16:54 +0400 Subject: s4-provision: Remove hard coded SD for CN=Sites container With the fix introduced by Nadya in changeset 622ef6aed82a2f2f7748c2a88535486af77487de we are now able to generate correct SD (at least the same as W2k3R2 with a Forest Level of 2003), so there is no need for this fix anymore as it makes SDs for Forest Level 2003 and lower incorrect. --- source4/scripting/python/samba/provision/__init__.py | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index 7c9f223d11..5aabd36c1a 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -94,19 +94,6 @@ def setup_path(file): # "get_schema_descriptor" is located in "schema.py" -def get_sites_descriptor(domain_sid): - sddl = "D:(A;;RPLCLORC;;;AU)" \ - "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \ - "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \ - "S:AI(AU;CISA;CCDCSDDT;;;WD)" \ - "(OU;CIIOSA;CR;;f0f8ffab-1191-11d0-a060-00aa006c33ed;WD)" \ - "(OU;CIIOSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \ - "(OU;CIIOSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \ - "(OU;CIIOSA;WP;3e10944c-c354-11d0-aff8-0000f80367c1;b7b13124-b82e-11d0-afee-0000f80367c1;WD)" - sec = security.descriptor.from_sddl(sddl, domain_sid) - return ndr_pack(sec) - - def get_config_descriptor(domain_sid): sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ @@ -1318,7 +1305,6 @@ def setup_samdb(path, session_info, provision_backend, lp, names, samdb.invocation_id = invocationid logger.info("Setting up sam.ldb configuration data") - descr = b64encode(get_sites_descriptor(domainsid)) setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { "CONFIGDN": names.configdn, "NETBIOSNAME": names.netbiosname, @@ -1330,7 +1316,6 @@ def setup_samdb(path, session_info, provision_backend, lp, names, "SERVERDN": names.serverdn, "FOREST_FUNCTIONALITY": str(forestFunctionality), "DOMAIN_FUNCTIONALITY": str(domainFunctionality), - "SITES_DESCRIPTOR": descr }) logger.info("Setting up display specifiers") -- cgit From 8a19e1ecfb716579e662d2d6b6bceeccbf7e7741 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 01:17:27 +0400 Subject: s4-upgradeprovision: skip versionNumber, it's used by GPO --- source4/scripting/bin/upgradeprovision | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 9bf09bd432..45c14e0027 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -113,6 +113,7 @@ hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace, "wellKnownObjects":replace, "privilege":never, "defaultSecurityDescriptor": replace, "rIDAvailablePool": never, + "versionNumber" : add, "rIDNextRID": add, "rIDUsedPool": never, "defaultSecurityDescriptor": replace + add, "isMemberOfPartialAttributeSet": delete, -- cgit From 89684895ee96741cdf2f88dc812496714df70fbb Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 01:17:44 +0400 Subject: s4-upgradeprovision: improve message output --- source4/scripting/python/samba/upgradehelpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 47ea660e43..e15523033f 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -440,7 +440,7 @@ def update_secrets(newsecrets_ldb, secrets_ldb, messagefunc): of the updated provision """ - messagefunc(SIMPLE, "update secrets.ldb") + messagefunc(SIMPLE, "Update of secrets.ldb") reference = newsecrets_ldb.search(expression="dn=@MODULES", base="", scope=SCOPE_SUBTREE) current = secrets_ldb.search(expression="dn=@MODULES", base="", -- cgit From 8a04863f0d630119c5f02b2708f50dd37dd37955 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 20:43:11 +0400 Subject: s4-sambatool: use correct way to call class methods --- source4/scripting/python/samba/netcmd/dbcheck.py | 107 ++++++++++++----------- 1 file changed, 54 insertions(+), 53 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index b0d77f2fd9..f433be5a95 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -38,58 +38,6 @@ def confirm(self, msg): return v.upper() in ['Y', 'YES'] -def empty_attribute(self, dn, attrname): - '''fix empty attributes''' - print("ERROR: Empty attribute %s in %s" % (attrname, dn)) - if not self.fix: - return - if not confirm(self, 'Remove empty attribute %s from %s?' % (attrname, dn)): - print("Not fixing empty attribute %s" % attrname) - return - - m = ldb.Message() - m.dn = dn - m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) - try: - self.samdb.modify(m, controls=["relax:0"], validate=False) - except Exception, msg: - print("Failed to remove empty attribute %s : %s" % (attrname, msg)) - return - print("Removed empty attribute %s" % attrname) - - -def normalise_mismatch(self, dn, attrname, values): - '''fix attribute normalisation errors''' - print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) - mod_list = [] - for val in values: - normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) - if len(normalised) != 1: - print("Unable to normalise value '%s'" % val) - mod_list.append((val, '')) - elif (normalised[0] != val): - print("value '%s' should be '%s'" % (val, normalised[0])) - mod_list.append((val, normalised[0])) - if not self.fix: - return - if not confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): - print("Not fixing attribute %s" % attrname) - return - - m = ldb.Message() - m.dn = dn - for i in range(0, len(mod_list)): - (val, nval) = mod_list[i] - m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) - if nval != '': - m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) - - try: - self.samdb.modify(m, controls=["relax:0"], validate=False) - except Exception, msg: - print("Failed to normalise attribute %s : %s" % (attrname, msg)) - return - print("Normalised attribute %s" % attrname) @@ -174,9 +122,62 @@ class cmd_dbcheck(Command): print('Checking %u objects' % len(res)) error_count = 0 for object in res: - error_count += check_object(self, object.dn) + error_count += self.check_object(self, object.dn) if error_count != 0 and not self.fix: print("Please use --fix to fix these errors") print('Checked %u objects (%u errors)' % (len(res), error_count)) if error_count != 0: sys.exit(1) + + def empty_attribute(self, dn, attrname): + '''fix empty attributes''' + print("ERROR: Empty attribute %s in %s" % (attrname, dn)) + if not self.fix: + return + if not confirm(self, 'Remove empty attribute %s from %s?' % (attrname, dn)): + print("Not fixing empty attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) + try: + self.samdb.modify(m, controls=["relax:0"], validate=False) + except Exception, msg: + print("Failed to remove empty attribute %s : %s" % (attrname, msg)) + return + print("Removed empty attribute %s" % attrname) + + + def normalise_mismatch(self, dn, attrname, values): + '''fix attribute normalisation errors''' + print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) + mod_list = [] + for val in values: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1: + print("Unable to normalise value '%s'" % val) + mod_list.append((val, '')) + elif (normalised[0] != val): + print("value '%s' should be '%s'" % (val, normalised[0])) + mod_list.append((val, normalised[0])) + if not self.fix: + return + if not confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): + print("Not fixing attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + for i in range(0, len(mod_list)): + (val, nval) = mod_list[i] + m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + if nval != '': + m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) + + try: + self.samdb.modify(m, controls=["relax:0"], validate=False) + except Exception, msg: + print("Failed to normalise attribute %s : %s" % (attrname, msg)) + return + print("Normalised attribute %s" % attrname) -- cgit From db0309160740afcdfb192cb55d15f906b15e0481 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 21:26:48 +0400 Subject: s4-samba-tool: use correct object notation ie. obj.method rather than method(obj, ...) --- source4/scripting/python/samba/netcmd/dbcheck.py | 68 +++++++++++------------- 1 file changed, 31 insertions(+), 37 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index f433be5a95..c1321d0f46 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -37,41 +37,6 @@ def confirm(self, msg): v = raw_input(msg + ' [y/N] ') return v.upper() in ['Y', 'YES'] - - - - -def check_object(self, dn): - '''check one object''' - if self.verbose: - print("Checking object %s" % dn) - res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) - if len(res) != 1: - print("Object %s disappeared during check" % dn) - return 1 - obj = res[0] - error_count = 0 - for attrname in obj: - if attrname == 'dn': - continue - - # check for empty attributes - for val in obj[attrname]: - if val == '': - empty_attribute(self, dn, attrname) - error_count += 1 - continue - - # check for incorrectly normalised attributes - for val in obj[attrname]: - normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) - if len(normalised) != 1 or normalised[0] != val: - normalise_mismatch(self, dn, attrname, obj[attrname]) - error_count += 1 - break - return error_count - - class cmd_dbcheck(Command): """check local AD database for errors""" synopsis = "dbcheck [options]" @@ -122,7 +87,7 @@ class cmd_dbcheck(Command): print('Checking %u objects' % len(res)) error_count = 0 for object in res: - error_count += self.check_object(self, object.dn) + error_count += self.check_object(object.dn) if error_count != 0 and not self.fix: print("Please use --fix to fix these errors") print('Checked %u objects (%u errors)' % (len(res), error_count)) @@ -148,6 +113,35 @@ class cmd_dbcheck(Command): return print("Removed empty attribute %s" % attrname) + def check_object(self, dn): + '''check one object''' + if self.verbose: + print("Checking object %s" % dn) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) + if len(res) != 1: + print("Object %s disappeared during check" % dn) + return 1 + obj = res[0] + error_count = 0 + for attrname in obj: + if attrname == 'dn': + continue + + # check for empty attributes + for val in obj[attrname]: + if val == '': + self.empty_attribute(dn, attrname) + error_count += 1 + continue + + # check for incorrectly normalised attributes + for val in obj[attrname]: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1 or normalised[0] != val: + self.normalise_mismatch(dn, attrname, obj[attrname]) + error_count += 1 + break + return error_count def normalise_mismatch(self, dn, attrname, values): '''fix attribute normalisation errors''' @@ -163,7 +157,7 @@ class cmd_dbcheck(Command): mod_list.append((val, normalised[0])) if not self.fix: return - if not confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): + if not self.confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): print("Not fixing attribute %s" % attrname) return -- cgit From bc549575dd0f80089dcaefcefeb4211c3771b8c6 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 21:27:32 +0400 Subject: s4-samba-tool: remove unused imports --- source4/scripting/python/samba/netcmd/dbcheck.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index c1321d0f46..5f75c3ee6c 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -18,11 +18,10 @@ # along with this program. If not, see . # -import samba, ldb, sys +import ldb, sys import samba.getopt as options from samba.auth import system_session from samba.samdb import SamDB -from samba.dcerpc import security from samba.netcmd import ( Command, CommandError, -- cgit From 9c94943d26d1076b0ef196698d7d0d2e3b0b80e4 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 Jun 2011 23:09:59 +0400 Subject: s4-sambatool: extract the confirm function in a separte module for reuse --- source4/scripting/python/samba/common.py | 33 ++++++++++++++++++++++++ source4/scripting/python/samba/netcmd/dbcheck.py | 13 +++------- 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 source4/scripting/python/samba/common.py (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/common.py b/source4/scripting/python/samba/common.py new file mode 100644 index 0000000000..a2a4962797 --- /dev/null +++ b/source4/scripting/python/samba/common.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# +# Samba common functions +# +# Copyright (C) Matthieu Patou +# +# 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 . +# + +def confirm(msg, forced = False): + """confirm an action with the user + :param msg: A string to print to the user + :param forced: Are the answer forced + """ + if forced: + print("%s [YES]" % msg) + return True + + v = raw_input(msg + ' [y/N] ') + return v.upper() in ['Y', 'YES'] + + diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 5f75c3ee6c..f28f9c6bbf 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -20,6 +20,7 @@ import ldb, sys import samba.getopt as options +from samba.common import confirm from samba.auth import system_session from samba.samdb import SamDB from samba.netcmd import ( @@ -28,14 +29,6 @@ from samba.netcmd import ( Option ) -def confirm(self, msg): - '''confirm an action with the user''' - if self.yes: - print("%s [YES]" % msg) - return True - v = raw_input(msg + ' [y/N] ') - return v.upper() in ['Y', 'YES'] - class cmd_dbcheck(Command): """check local AD database for errors""" synopsis = "dbcheck [options]" @@ -98,7 +91,7 @@ class cmd_dbcheck(Command): print("ERROR: Empty attribute %s in %s" % (attrname, dn)) if not self.fix: return - if not confirm(self, 'Remove empty attribute %s from %s?' % (attrname, dn)): + if not confirm('Remove empty attribute %s from %s?' % (attrname, dn), self.yes): print("Not fixing empty attribute %s" % attrname) return @@ -156,7 +149,7 @@ class cmd_dbcheck(Command): mod_list.append((val, normalised[0])) if not self.fix: return - if not self.confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)): + if not confirm('Fix normalisation for %s from %s?' % (attrname, dn), self.yes): print("Not fixing attribute %s" % attrname) return -- cgit From 957b1ff183cf713bebc4cc9a32cabacc1e86b13e Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 20 Jun 2011 01:00:48 +0400 Subject: s4: create script to find provision ranges for old provision without this information --- source4/scripting/bin/findprovisionusnranges | 174 +++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100755 source4/scripting/bin/findprovisionusnranges (limited to 'source4/scripting') diff --git a/source4/scripting/bin/findprovisionusnranges b/source4/scripting/bin/findprovisionusnranges new file mode 100755 index 0000000000..c91e42e936 --- /dev/null +++ b/source4/scripting/bin/findprovisionusnranges @@ -0,0 +1,174 @@ +#!/usr/bin/python +# +# Helper for determining USN ranges created of modified by provision and +# upgradeprovision. +# Copyright (C) Matthieu Patou 2009-2011 +# +# +# 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 . +# + +import sys +import optparse +import tempfile +sys.path.insert(0, "bin/python") + +from samba.credentials import DONT_USE_KERBEROS +from samba.auth import system_session +from samba import Ldb +import ldb + +import samba.getopt as options +from samba import param +from samba import _glue +from samba.upgradehelpers import get_paths +from samba.ndr import ndr_unpack +from samba.dcerpc import drsblobs, misc + +parser = optparse.OptionParser("provision [options]") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +parser.add_option_group(options.VersionOptions(parser)) +parser.add_option("--storedir", type="string", help="Directory where to store result files") +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) +session = system_session() +paths = get_paths(param, smbconf=smbconf) +basedn="DC=" + lp.get("realm").replace(".",",DC=") +samdb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp) + +hash_id = {} +ldif = "" +nb_obj = 0 + +res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"]) + +invocation = None +if res and len(res) == 1 and res[0]["dsServiceName"] != None: + dn = ldb.Dn(samdb, str(res[0]["dsServiceName"])) + res = samdb.search(base=str(dn), scope=ldb.SCOPE_BASE, attrs=["invocationId"], + controls=["search_options:1:2"]) + + if res and len(res) == 1 and res[0]["invocationId"]: + invocation = str(ndr_unpack(misc.GUID, res[0]["invocationId"][0])) + else: + print "Unable to find invocation ID" + sys.exit(1) +else: + print "Unable to find attribute dsServiceName in rootDSE" + sys.exit(1) + +res = samdb.search(base=basedn, expression="objectClass=*", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData"], + controls=["search_options:1:2"]) + +for e in res: + nb_obj = nb_obj + 1 + obj = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(e["replPropertyMetaData"])).ctr + + for o in obj.array: + # like a timestamp but with the resolution of 1 minute + minutestamp =_glue.nttime2unix(o.originating_change_time)/60 + hash_ts = hash_id.get(str(o.originating_invocation_id)) + if hash_ts == None: + ob = {} + ob["min"] = o.originating_usn + ob["max"] = o.originating_usn + ob["num"] = 1 + ob["list"] = [str(e.dn)] + hash_ts = {} + else: + ob = hash_ts.get(minutestamp) + if ob == None: + ob = {} + ob["min"] = o.originating_usn + ob["max"] = o.originating_usn + ob["num"] = 1 + ob["list"] = [str(e.dn)] + else: + if ob["min"] > o.originating_usn: + ob["min"] = o.originating_usn + if ob["max"] < o.originating_usn: + ob["max"] = o.originating_usn + if not (str(e.dn) in ob["list"]): + ob["num"] = ob["num"] + 1 + ob["list"].append(str(e.dn)) + hash_ts[minutestamp] = ob + hash_id[str(o.originating_invocation_id)] = hash_ts + +minobj = 5 +print "Here is a list of changes that modified more than %d objects in 1 minute." % minobj +print "Usually changes made by provision and upgradeprovision are those who affect a couple"\ + " of hundred of objects or more" +print "Total number of objects: %d" % nb_obj +print + +for id in hash_id: + hash_ts = hash_id[id] + sorted_keys = [] + sorted_keys.extend(hash_ts.keys()) + sorted_keys.sort() + + kept_record = [] + for k in sorted_keys: + obj = hash_ts[k] + if obj["num"] > minobj: + dt = _glue.nttime2string(_glue.unix2nttime(k*60)) + print "%s # of modification: %d \tmin: %d max: %d" % (dt , obj["num"], + obj["min"], + obj["max"]) + if hash_ts[k]["num"] > 600: + kept_record.append(k) + + # Let's try to concatenate consecutive block if they are in the almost same minutestamp + for i in range(0, len(kept_record)): + if i != 0: + key1 = kept_record[i] + key2 = kept_record[i-1] + if key1 - key2 == 1: + # previous record is just 1 minute away from current + if int(hash_ts[key1]["min"]) == int(hash_ts[key2]["max"]) + 1: + # Copy the highest USN in the previous record + # and mark the current as skipped + hash_ts[key2]["max"] = hash_ts[key1]["max"] + hash_ts[key1]["skipped"] = True + + for k in kept_record: + obj = hash_ts[k] + if obj.get("skipped") == None: + ldif = "%slastProvisionUSN: %d-%d;%s\n" % (ldif, obj["min"], + obj["max"], id) + +if ldif != "": + dest = opts.storedir + if dest == None: + dest = "/tmp" + + file = tempfile.mktemp(dir=dest, prefix="usnprov", suffix=".ldif") + print + print "To track the USNs modified/created by provision and upgrade proivsion," + print " the following ranges are proposed to be added to your provision sam.ldb: \n%s" % ldif + print "We recommend to review them, and if it's correct to integrate the following ldif: %s in your sam.ldb" % file + print "You can load this file like this: ldbadd -H %s %s\n"%(str(paths.samdb),file) + ldif = "dn: @PROVISION\nprovisionnerID: %s\n%s" % (invocation, ldif) + open(file,'w').write(ldif) + -- cgit From 01ce078ed166635c29e89bd012c82e3612393f28 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Mon, 20 Jun 2011 01:05:04 +0400 Subject: s4-upgradeprovision: propose the use of findprovisionranges if no ranges are present Autobuild-User: Matthieu Patou Autobuild-Date: Mon Jun 20 00:30:59 CEST 2011 on sn-devel-104 --- source4/scripting/bin/upgradeprovision | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 45c14e0027..f10a9fcc9c 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -44,6 +44,7 @@ from ldb import (SCOPE_SUBTREE, SCOPE_BASE, FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE, MessageElement, Message, Dn, LdbError) from samba import param, dsdb, Ldb +from samba.common import confirm from samba.provision import (get_domain_descriptor, find_provision_key_parameters, get_config_descriptor, ProvisioningError, get_last_provision_usn, @@ -1729,6 +1730,19 @@ if __name__ == '__main__': message(CHANGE, "Old style for usn ranges used") lastProvisionUSNs[str(names.invocation)] = lastProvisionUSNs["default"] del lastProvisionUSNs["default"] + else: + message(SIMPLE, "Your provision lacks provision range information") + if confirm("Do you want to run findprovisionusnranges to try to find them ?", False): + ldbs.groupedRollback() + os.system("%s %s %s %s %s" % (os.path.join(os.path.dirname(sys.argv[0]), + "findprovisionusnranges"), + "--storedir", + paths.private_dir, + "-s", + smbconf)) + message(SIMPLE, "Once you applied/adapted the change(s) please restart the upgradeprovision script") + sys.exit(0) + # Objects will be created with the admin session # (not anymore system session) adm_session = admin_session(lp, str(names.domainsid)) -- cgit From 5eecc854236f0b943aaa89e0c3a46f9fbd208ca9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Jun 2011 18:40:33 +0930 Subject: tdb2: create tdb2 versions of various testing TDBs. Soon, TDB2 will handle tdb1 files, but until then, we substitute. Signed-off-by: Rusty Russell --- source4/scripting/python/samba/samba3.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py index 2c323bd0b4..ae5b20edd2 100644 --- a/source4/scripting/python/samba/samba3.py +++ b/source4/scripting/python/samba/samba3.py @@ -50,9 +50,12 @@ class TdbDatabase(object): def __init__(self, file): """Open a file. - :param file: Path of the file to open. + :param file: Path of the file to open (appending "2" if TDB2 enabled). """ - self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) + if tdb.__version__.startswith("2"): + self.tdb = tdb.Tdb(file + "2", flags=os.O_RDONLY) + else: + self.tdb = tdb.Tdb(file, flags=os.O_RDONLY) self._check_version() def _check_version(self): -- cgit From c4a7908f46e7005f323eeca5fd38ec9e88a54aa9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 12:23:05 +1000 Subject: samba-tool: try to keep dbcheck.py in a logical ordering keep individual error handlers together and separate from driver code --- source4/scripting/python/samba/netcmd/dbcheck.py | 67 ++++++++++++++---------- 1 file changed, 38 insertions(+), 29 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index f28f9c6bbf..4ec1365f14 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -86,6 +86,9 @@ class cmd_dbcheck(Command): if error_count != 0: sys.exit(1) + + ################################################################ + # handle empty attributes def empty_attribute(self, dn, attrname): '''fix empty attributes''' print("ERROR: Empty attribute %s in %s" % (attrname, dn)) @@ -105,36 +108,9 @@ class cmd_dbcheck(Command): return print("Removed empty attribute %s" % attrname) - def check_object(self, dn): - '''check one object''' - if self.verbose: - print("Checking object %s" % dn) - res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) - if len(res) != 1: - print("Object %s disappeared during check" % dn) - return 1 - obj = res[0] - error_count = 0 - for attrname in obj: - if attrname == 'dn': - continue - - # check for empty attributes - for val in obj[attrname]: - if val == '': - self.empty_attribute(dn, attrname) - error_count += 1 - continue - - # check for incorrectly normalised attributes - for val in obj[attrname]: - normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) - if len(normalised) != 1 or normalised[0] != val: - self.normalise_mismatch(dn, attrname, obj[attrname]) - error_count += 1 - break - return error_count + ################################################################ + # handle normalisation mismatches def normalise_mismatch(self, dn, attrname, values): '''fix attribute normalisation errors''' print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) @@ -167,3 +143,36 @@ class cmd_dbcheck(Command): print("Failed to normalise attribute %s : %s" % (attrname, msg)) return print("Normalised attribute %s" % attrname) + + + ################################################################ + # check one object - calls to individual error handlers above + def check_object(self, dn): + '''check one object''' + if self.verbose: + print("Checking object %s" % dn) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) + if len(res) != 1: + print("Object %s disappeared during check" % dn) + return 1 + obj = res[0] + error_count = 0 + for attrname in obj: + if attrname == 'dn': + continue + + # check for empty attributes + for val in obj[attrname]: + if val == '': + self.empty_attribute(dn, attrname) + error_count += 1 + continue + + # check for incorrectly normalised attributes + for val in obj[attrname]: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + if len(normalised) != 1 or normalised[0] != val: + self.normalise_mismatch(dn, attrname, obj[attrname]) + error_count += 1 + break + return error_count -- cgit From 202f0a4b576d78928a403b68f3e057d3a425bddf Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 14:41:50 +1000 Subject: pydsdb: added get_syntax_oid_from_lDAPDisplayName() this gives you access to the syntax oid of an attribute Pair-Programmed-With: Andrew Bartlett --- source4/scripting/python/samba/samdb.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index 53346e8670..72ee472764 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -476,9 +476,14 @@ accountExpires: %u def get_attid_from_lDAPDisplayName(self, ldap_display_name, is_schema_nc=False): + '''return the attribute ID for a LDAP attribute as an integer as found in DRSUAPI''' return dsdb._dsdb_get_attid_from_lDAPDisplayName(self, ldap_display_name, is_schema_nc) + def get_syntax_oid_from_lDAPDisplayName(self, ldap_display_name): + '''return the syntax OID for a LDAP attribute as a string''' + return dsdb._dsdb_get_syntax_oid_from_lDAPDisplayName(self, ldap_display_name) + def set_ntds_settings_dn(self, ntds_settings_dn): """Set the NTDS Settings DN, as would be returned on the dsServiceName rootDSE attribute. -- cgit From 9e766f019bff74ec9c1d5df326cdea2c7fe05e2a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 14:44:36 +1000 Subject: samba-tool: added missing GUID component checks to dbcheck Pair-Programmed-With: Andrew Bartlett Autobuild-User: Andrew Tridgell Autobuild-Date: Wed Jun 22 07:59:30 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/netcmd/dbcheck.py | 97 +++++++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 4ec1365f14..4c9e0a1af5 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -20,15 +20,42 @@ import ldb, sys import samba.getopt as options +from samba import dsdb from samba.common import confirm from samba.auth import system_session from samba.samdb import SamDB +from samba.dcerpc import misc from samba.netcmd import ( Command, CommandError, Option ) + +class dsdb_DN(object): + '''a class to manipulate DN components''' + + def __init__(self, samdb, dnstring, syntax_oid): + if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN ]: + colons = dnstring.split(':') + if len(colons) < 4: + raise Exception("invalid DN prefix") + prefix_len = 4 + len(colons[1]) + int(colons[1]) + self.prefix = dnstring[0:prefix_len] + self.dnstring = dnstring[prefix_len:] + else: + self.dnstring = dnstring + self.prefix = '' + try: + self.dn = ldb.Dn(samdb, self.dnstring) + except Exception, msg: + print("ERROR: bad DN string '%s'" % self.dnstring) + raise + + def __str__(self): + return self.prefix + str(self.dn.extended_str(mode=1)) + + class cmd_dbcheck(Command): """check local AD database for errors""" synopsis = "dbcheck [options]" @@ -89,7 +116,7 @@ class cmd_dbcheck(Command): ################################################################ # handle empty attributes - def empty_attribute(self, dn, attrname): + def err_empty_attribute(self, dn, attrname): '''fix empty attributes''' print("ERROR: Empty attribute %s in %s" % (attrname, dn)) if not self.fix: @@ -101,6 +128,8 @@ class cmd_dbcheck(Command): m = ldb.Message() m.dn = dn m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) + if self.verbose: + print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m, controls=["relax:0"], validate=False) except Exception, msg: @@ -111,7 +140,7 @@ class cmd_dbcheck(Command): ################################################################ # handle normalisation mismatches - def normalise_mismatch(self, dn, attrname, values): + def err_normalise_mismatch(self, dn, attrname, values): '''fix attribute normalisation errors''' print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) mod_list = [] @@ -137,6 +166,8 @@ class cmd_dbcheck(Command): if nval != '': m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) + if self.verbose: + print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m, controls=["relax:0"], validate=False) except Exception, msg: @@ -145,6 +176,55 @@ class cmd_dbcheck(Command): print("Normalised attribute %s" % attrname) + ################################################################ + # handle a missing GUID extended DN component + def err_missing_dn_GUID(self, dn, attrname, val, dsdb_dn): + print("ERROR: missing GUID component for %s in object %s - %s" % (attrname, dn, val)) + try: + res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, attrs=['objectGUID']) + except LdbError, (enum, estr): + print("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) + return + guid = res[0]['objectGUID'][0] + guidstr = str(misc.GUID(guid)) + dsdb_dn.dn.set_extended_component("GUID", guid) + + if not confirm('Add GUID %s giving DN %s?' % (guidstr, str(dsdb_dn))): + print("Not fixing missing GUID") + return + m = ldb.Message() + m.dn = dn + m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) + if self.verbose: + print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m) + except Exception, msg: + print("Failed to fix missing GUID on attribute %s : %s" % (attrname, msg)) + return + print("Fixed missing GUID on attribute %s" % attrname) + + + + ################################################################ + # specialised checking for a dn attribute + def check_dn(self, obj, attrname, syntax_oid): + '''check a DN attribute for correctness''' + error_count = 0 + for val in obj[attrname]: + dsdb_dn = dsdb_DN(self.samdb, val, syntax_oid) + + # all DNs should have a GUID component + guid = dsdb_dn.dn.get_extended_component("GUID") + if guid is None: + error_count += 1 + self.err_missing_dn_GUID(obj.dn, attrname, val, dsdb_dn) + + return 0 + + + ################################################################ # check one object - calls to individual error handlers above def check_object(self, dn): @@ -164,15 +244,24 @@ class cmd_dbcheck(Command): # check for empty attributes for val in obj[attrname]: if val == '': - self.empty_attribute(dn, attrname) + self.err_empty_attribute(dn, attrname) error_count += 1 continue + # get the syntax oid for the attribute, so we can can have + # special handling for some specific attribute types + syntax_oid = self.samdb.get_syntax_oid_from_lDAPDisplayName(attrname) + + if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_OR_NAME, + dsdb.DSDB_SYNTAX_STRING_DN, ldb.LDB_SYNTAX_DN ]: + # it's some form of DN, do specialised checking on those + error_count += self.check_dn(obj, attrname, syntax_oid) + # check for incorrectly normalised attributes for val in obj[attrname]: normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) if len(normalised) != 1 or normalised[0] != val: - self.normalise_mismatch(dn, attrname, obj[attrname]) + self.err_normalise_mismatch(dn, attrname, obj[attrname]) error_count += 1 break return error_count -- cgit From ff8cdeecfc28be396dcbdc4af6b7e60ab9de45f1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 17:08:28 +1000 Subject: samba-tool: expanded dbcheck DN checking this now checks for bad GUID elements in DN links, and offers to fix them when possible Pair-Programmed-With: Andrew Bartlett --- source4/scripting/python/samba/netcmd/dbcheck.py | 125 +++++++++++++++++++---- 1 file changed, 104 insertions(+), 21 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 4c9e0a1af5..d7a492836e 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -21,7 +21,7 @@ import ldb, sys import samba.getopt as options from samba import dsdb -from samba.common import confirm +from samba import common from samba.auth import system_session from samba.samdb import SamDB from samba.dcerpc import misc @@ -74,7 +74,7 @@ class cmd_dbcheck(Command): Option("--fix", dest="fix", default=False, action='store_true', help='Fix any errors found'), Option("--yes", dest="yes", default=False, action='store_true', - help="don't confirm changes, just do them all"), + help="don't confirm changes, just do them all as a single transaction"), Option("--cross-ncs", dest="cross_ncs", default=False, action='store_true', help="cross naming context boundaries"), Option("-v", "--verbose", dest="verbose", action="store_true", default=False, @@ -102,6 +102,9 @@ class cmd_dbcheck(Command): if cross_ncs: controls.append("search_options:1:2") + if self.yes and self.fix: + self.samdb.transaction_start() + res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) print('Checking %u objects' % len(res)) error_count = 0 @@ -110,18 +113,30 @@ class cmd_dbcheck(Command): if error_count != 0 and not self.fix: print("Please use --fix to fix these errors") print('Checked %u objects (%u errors)' % (len(res), error_count)) + + if self.yes and self.fix: + self.samdb.transaction_commit() + if error_count != 0: sys.exit(1) + + ################################################################ + # a local confirm function that obeys the --fix and --yes options + def confirm(self, msg): + '''confirm a change''' + if not self.fix: + return False + return common.confirm(msg, forced=self.yes) + + ################################################################ # handle empty attributes def err_empty_attribute(self, dn, attrname): '''fix empty attributes''' print("ERROR: Empty attribute %s in %s" % (attrname, dn)) - if not self.fix: - return - if not confirm('Remove empty attribute %s from %s?' % (attrname, dn), self.yes): + if not self.confirm('Remove empty attribute %s from %s?' % (attrname, dn)): print("Not fixing empty attribute %s" % attrname) return @@ -152,9 +167,7 @@ class cmd_dbcheck(Command): elif (normalised[0] != val): print("value '%s' should be '%s'" % (val, normalised[0])) mod_list.append((val, normalised[0])) - if not self.fix: - return - if not confirm('Fix normalisation for %s from %s?' % (attrname, dn), self.yes): + if not self.confirm('Fix normalisation for %s from %s?' % (attrname, dn)): print("Not fixing attribute %s" % attrname) return @@ -178,19 +191,18 @@ class cmd_dbcheck(Command): ################################################################ # handle a missing GUID extended DN component - def err_missing_dn_GUID(self, dn, attrname, val, dsdb_dn): - print("ERROR: missing GUID component for %s in object %s - %s" % (attrname, dn, val)) + def err_incorrect_dn_GUID(self, dn, attrname, val, dsdb_dn, errstr): + print("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) try: - res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, attrs=['objectGUID']) - except LdbError, (enum, estr): + res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, + attrs=[], controls=["extended_dn:1:1"]) + except ldb.LdbError, (enum, estr): print("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) return - guid = res[0]['objectGUID'][0] - guidstr = str(misc.GUID(guid)) - dsdb_dn.dn.set_extended_component("GUID", guid) + dsdb_dn.dn = res[0].dn - if not confirm('Add GUID %s giving DN %s?' % (guidstr, str(dsdb_dn))): - print("Not fixing missing GUID") + if not self.confirm('Change DN to %s?' % str(dsdb_dn)): + print("Not fixing %s" % errstr) return m = ldb.Message() m.dn = dn @@ -201,10 +213,53 @@ class cmd_dbcheck(Command): try: self.samdb.modify(m) except Exception, msg: - print("Failed to fix missing GUID on attribute %s : %s" % (attrname, msg)) + print("Failed to fix %s on attribute %s : %s" % (errstr, attrname, msg)) return - print("Fixed missing GUID on attribute %s" % attrname) + print("Fixed %s on attribute %s" % (errstr, attrname)) + + ################################################################ + # handle a DN pointing to a deleted object + def err_deleted_dn(self, dn, attrname, val, dsdb_dn, correct_dn): + print("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val)) + print("Target GUID points at deleted DN %s" % correct_dn) + if not self.confirm('Remove DN?'): + print("Not removing") + return + m = ldb.Message() + m.dn = dn + m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + if self.verbose: + print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m) + except Exception, msg: + print("Failed to remove deleted DN attribute %s : %s" % (attrname, msg)) + return + print("Removed deleted DN on attribute %s" % attrname) + + + ################################################################ + # handle a DN string being incorrect + def err_dn_target_mismatch(self, dn, attrname, val, dsdb_dn, correct_dn): + print("ERROR: incorrect DN string component for %s in object %s - %s" % (attrname, dn, val)) + dsdb_dn.dn = correct_dn + + if not self.confirm('Change DN to %s?' % str(dsdb_dn)): + print("Not fixing %s" % errstr) + return + m = ldb.Message() + m.dn = dn + m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) + if self.verbose: + print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m) + except Exception, msg: + print("Failed to fix incorrect DN string on attribute %s : %s" % (attrname, msg)) + return + print("Fixed incorrect DN string on attribute %s" % (attrname)) ################################################################ @@ -219,9 +274,37 @@ class cmd_dbcheck(Command): guid = dsdb_dn.dn.get_extended_component("GUID") if guid is None: error_count += 1 - self.err_missing_dn_GUID(obj.dn, attrname, val, dsdb_dn) + self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "missing GUID") + continue + + guidstr = str(misc.GUID(guid)) + + # check its the right GUID + try: + res = self.samdb.search(base="" % guidstr, scope=ldb.SCOPE_BASE, + attrs=['isDeleted'], controls=["extended_dn:1:1", "show_deleted:1"]) + except ldb.LdbError, (enum, estr): + error_count += 1 + self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "incorrect GUID") + continue + + # the target DN might be deleted + if (dsdb_dn.prefix != "B:32:18E2EA80684F11D2B9AA00C04F79F805:" and + 'isDeleted' in res[0] and + res[0]['isDeleted'][0].upper() == "TRUE"): + # note that we don't check this for the special wellKnownObjects prefix + # for Deleted Objects, as we expect that to be deleted + error_count += 1 + self.err_deleted_dn(obj.dn, attrname, val, dsdb_dn, res[0].dn) + continue + + # check the DN matches in string form + if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): + error_count += 1 + self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn) + continue - return 0 + return error_count -- cgit From 6d1fe054dd93b8d282fcf515fc62f5d5ab72e6a8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 17:38:19 +1000 Subject: samba-tool: allow for running dbcheck against a remove ldap server this is useful for running it against a Windows server --- source4/scripting/python/samba/netcmd/dbcheck.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index d7a492836e..93fe3f6c37 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -79,15 +79,22 @@ class cmd_dbcheck(Command): help="cross naming context boundaries"), Option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print more details of checking"), + Option("-H", help="LDB URL for database or target server (defaults to local SAM database)", type=str), ] - def run(self, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, + def run(self, H=None, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, scope="SUB", credopts=None, sambaopts=None, versionopts=None): self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp, fallback_machine=True) - self.samdb = SamDB(session_info=system_session(), url=None, + self.samdb = SamDB(session_info=system_session(), url=H, credentials=self.creds, lp=self.lp) + if H is None: + self.local_samdb = self.samdb + else: + self.local_samdb = SamDB(session_info=system_session(), url=None, + credentials=self.creds, lp=self.lp) + self.verbose = verbose self.fix = fix self.yes = yes @@ -99,6 +106,8 @@ class cmd_dbcheck(Command): self.search_scope = scope_map[scope] controls = [] + if H is not None: + controls.append('paged_results:1:1000') if cross_ncs: controls.append("search_options:1:2") @@ -160,7 +169,7 @@ class cmd_dbcheck(Command): print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) mod_list = [] for val in values: - normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + normalised = self.samdb.dsdb_normalise_attributes(self.local_samdb, attrname, [val]) if len(normalised) != 1: print("Unable to normalise value '%s'" % val) mod_list.append((val, '')) @@ -333,7 +342,7 @@ class cmd_dbcheck(Command): # get the syntax oid for the attribute, so we can can have # special handling for some specific attribute types - syntax_oid = self.samdb.get_syntax_oid_from_lDAPDisplayName(attrname) + syntax_oid = self.local_samdb.get_syntax_oid_from_lDAPDisplayName(attrname) if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_OR_NAME, dsdb.DSDB_SYNTAX_STRING_DN, ldb.LDB_SYNTAX_DN ]: @@ -342,7 +351,7 @@ class cmd_dbcheck(Command): # check for incorrectly normalised attributes for val in obj[attrname]: - normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val]) + normalised = self.samdb.dsdb_normalise_attributes(self.local_samdb, attrname, [val]) if len(normalised) != 1 or normalised[0] != val: self.err_normalise_mismatch(dn, attrname, obj[attrname]) error_count += 1 -- cgit From 9be9f0e43c9312094a42efa236791dfcd95dc9f9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 19:32:45 +1000 Subject: samba-tool: added --quiet option to dbcheck this will be used to allow for other tools (such as provision) to call into dbcheck without generating a lot of noise --- source4/scripting/python/samba/netcmd/dbcheck.py | 78 +++++++++++++----------- 1 file changed, 43 insertions(+), 35 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 93fe3f6c37..ccc6355193 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -79,10 +79,12 @@ class cmd_dbcheck(Command): help="cross naming context boundaries"), Option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print more details of checking"), + Option("--quiet", dest="quiet", action="store_true", default=False, + help="don't print details of checking"), Option("-H", help="LDB URL for database or target server (defaults to local SAM database)", type=str), ] - def run(self, H=None, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, + def run(self, H=None, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, quiet=False, scope="SUB", credopts=None, sambaopts=None, versionopts=None): self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp, fallback_machine=True) @@ -98,6 +100,7 @@ class cmd_dbcheck(Command): self.verbose = verbose self.fix = fix self.yes = yes + self.quiet = quiet scope_map = { "SUB": ldb.SCOPE_SUBTREE, "BASE":ldb.SCOPE_BASE, "ONE":ldb.SCOPE_ONELEVEL } scope = scope.upper() @@ -115,13 +118,13 @@ class cmd_dbcheck(Command): self.samdb.transaction_start() res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) - print('Checking %u objects' % len(res)) + self.report('Checking %u objects' % len(res)) error_count = 0 for object in res: error_count += self.check_object(object.dn) if error_count != 0 and not self.fix: - print("Please use --fix to fix these errors") - print('Checked %u objects (%u errors)' % (len(res), error_count)) + self.report("Please use --fix to fix these errors") + self.report('Checked %u objects (%u errors)' % (len(res), error_count)) if self.yes and self.fix: self.samdb.transaction_commit() @@ -130,6 +133,11 @@ class cmd_dbcheck(Command): sys.exit(1) + def report(self, msg): + '''print a message unless quiet is set''' + if not self.quiet: + print(msg) + ################################################################ # a local confirm function that obeys the --fix and --yes options @@ -144,40 +152,40 @@ class cmd_dbcheck(Command): # handle empty attributes def err_empty_attribute(self, dn, attrname): '''fix empty attributes''' - print("ERROR: Empty attribute %s in %s" % (attrname, dn)) + self.report("ERROR: Empty attribute %s in %s" % (attrname, dn)) if not self.confirm('Remove empty attribute %s from %s?' % (attrname, dn)): - print("Not fixing empty attribute %s" % attrname) + self.report("Not fixing empty attribute %s" % attrname) return m = ldb.Message() m.dn = dn m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) if self.verbose: - print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m, controls=["relax:0"], validate=False) except Exception, msg: - print("Failed to remove empty attribute %s : %s" % (attrname, msg)) + self.report("Failed to remove empty attribute %s : %s" % (attrname, msg)) return - print("Removed empty attribute %s" % attrname) + self.report("Removed empty attribute %s" % attrname) ################################################################ # handle normalisation mismatches def err_normalise_mismatch(self, dn, attrname, values): '''fix attribute normalisation errors''' - print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) + self.report("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) mod_list = [] for val in values: normalised = self.samdb.dsdb_normalise_attributes(self.local_samdb, attrname, [val]) if len(normalised) != 1: - print("Unable to normalise value '%s'" % val) + self.report("Unable to normalise value '%s'" % val) mod_list.append((val, '')) elif (normalised[0] != val): - print("value '%s' should be '%s'" % (val, normalised[0])) + self.report("value '%s' should be '%s'" % (val, normalised[0])) mod_list.append((val, normalised[0])) if not self.confirm('Fix normalisation for %s from %s?' % (attrname, dn)): - print("Not fixing attribute %s" % attrname) + self.report("Not fixing attribute %s" % attrname) return m = ldb.Message() @@ -189,86 +197,86 @@ class cmd_dbcheck(Command): m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) if self.verbose: - print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m, controls=["relax:0"], validate=False) except Exception, msg: - print("Failed to normalise attribute %s : %s" % (attrname, msg)) + self.report("Failed to normalise attribute %s : %s" % (attrname, msg)) return - print("Normalised attribute %s" % attrname) + self.report("Normalised attribute %s" % attrname) ################################################################ # handle a missing GUID extended DN component def err_incorrect_dn_GUID(self, dn, attrname, val, dsdb_dn, errstr): - print("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) + self.report("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) try: res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, attrs=[], controls=["extended_dn:1:1"]) except ldb.LdbError, (enum, estr): - print("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) + self.report("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) return dsdb_dn.dn = res[0].dn if not self.confirm('Change DN to %s?' % str(dsdb_dn)): - print("Not fixing %s" % errstr) + self.report("Not fixing %s" % errstr) return m = ldb.Message() m.dn = dn m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) if self.verbose: - print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m) except Exception, msg: - print("Failed to fix %s on attribute %s : %s" % (errstr, attrname, msg)) + self.report("Failed to fix %s on attribute %s : %s" % (errstr, attrname, msg)) return - print("Fixed %s on attribute %s" % (errstr, attrname)) + self.report("Fixed %s on attribute %s" % (errstr, attrname)) ################################################################ # handle a DN pointing to a deleted object def err_deleted_dn(self, dn, attrname, val, dsdb_dn, correct_dn): - print("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val)) - print("Target GUID points at deleted DN %s" % correct_dn) + self.report("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val)) + self.report("Target GUID points at deleted DN %s" % correct_dn) if not self.confirm('Remove DN?'): - print("Not removing") + self.report("Not removing") return m = ldb.Message() m.dn = dn m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) if self.verbose: - print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m) except Exception, msg: - print("Failed to remove deleted DN attribute %s : %s" % (attrname, msg)) + self.report("Failed to remove deleted DN attribute %s : %s" % (attrname, msg)) return - print("Removed deleted DN on attribute %s" % attrname) + self.report("Removed deleted DN on attribute %s" % attrname) ################################################################ # handle a DN string being incorrect def err_dn_target_mismatch(self, dn, attrname, val, dsdb_dn, correct_dn): - print("ERROR: incorrect DN string component for %s in object %s - %s" % (attrname, dn, val)) + self.report("ERROR: incorrect DN string component for %s in object %s - %s" % (attrname, dn, val)) dsdb_dn.dn = correct_dn if not self.confirm('Change DN to %s?' % str(dsdb_dn)): - print("Not fixing %s" % errstr) + self.report("Not fixing %s" % errstr) return m = ldb.Message() m.dn = dn m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) if self.verbose: - print(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) try: self.samdb.modify(m) except Exception, msg: - print("Failed to fix incorrect DN string on attribute %s : %s" % (attrname, msg)) + self.report("Failed to fix incorrect DN string on attribute %s : %s" % (attrname, msg)) return - print("Fixed incorrect DN string on attribute %s" % (attrname)) + self.report("Fixed incorrect DN string on attribute %s" % (attrname)) ################################################################ @@ -322,10 +330,10 @@ class cmd_dbcheck(Command): def check_object(self, dn): '''check one object''' if self.verbose: - print("Checking object %s" % dn) + self.report("Checking object %s" % dn) res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) if len(res) != 1: - print("Object %s disappeared during check" % dn) + self.report("Object %s disappeared during check" % dn) return 1 obj = res[0] error_count = 0 -- cgit From 7fff636bce2576a63170bf3cc555eb85b8fefd67 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 20:01:58 +1000 Subject: samba-tool: make the dbcheck class available outside of samba-tool this will be used in provision, and probably in upgradeprovision as well --- source4/scripting/python/samba/dbchecker.py | 308 +++++++++++++++++++++++ source4/scripting/python/samba/netcmd/dbcheck.py | 301 ++-------------------- 2 files changed, 324 insertions(+), 285 deletions(-) create mode 100644 source4/scripting/python/samba/dbchecker.py (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py new file mode 100644 index 0000000000..1687c82d83 --- /dev/null +++ b/source4/scripting/python/samba/dbchecker.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python +# +# Samba4 AD database checker +# +# Copyright (C) Andrew Tridgell 2011 +# +# 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 . +# + +import ldb, sys +from samba import dsdb +from samba import common +from samba.dcerpc import misc + + +class dsdb_DN(object): + '''a class to manipulate DN components''' + + def __init__(self, samdb, dnstring, syntax_oid): + if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN ]: + colons = dnstring.split(':') + if len(colons) < 4: + raise Exception("invalid DN prefix") + prefix_len = 4 + len(colons[1]) + int(colons[1]) + self.prefix = dnstring[0:prefix_len] + self.dnstring = dnstring[prefix_len:] + else: + self.dnstring = dnstring + self.prefix = '' + try: + self.dn = ldb.Dn(samdb, self.dnstring) + except Exception, msg: + print("ERROR: bad DN string '%s'" % self.dnstring) + raise + + def __str__(self): + return self.prefix + str(self.dn.extended_str(mode=1)) + +class dbcheck(object): + """check a SAM database for errors""" + + def __init__(self, samdb, samdb_schema=None, verbose=False, fix=False, yes=False, quiet=False): + self.samdb = samdb + self.samdb_schema = (samdb_schema or samdb) + self.verbose = verbose + self.fix = fix + self.yes = yes + self.quiet = quiet + + def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=[]): + '''perform a database check, returning the number of errors found''' + self.search_scope = scope + + res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) + self.report('Checking %u objects' % len(res)) + error_count = 0 + for object in res: + error_count += self.check_object(object.dn) + if error_count != 0 and not self.fix: + self.report("Please use --fix to fix these errors") + self.report('Checked %u objects (%u errors)' % (len(res), error_count)) + + return error_count + + + def report(self, msg): + '''print a message unless quiet is set''' + if not self.quiet: + print(msg) + + + ################################################################ + # a local confirm function that obeys the --fix and --yes options + def confirm(self, msg): + '''confirm a change''' + if not self.fix: + return False + return common.confirm(msg, forced=self.yes) + + + ################################################################ + # handle empty attributes + def err_empty_attribute(self, dn, attrname): + '''fix empty attributes''' + self.report("ERROR: Empty attribute %s in %s" % (attrname, dn)) + if not self.confirm('Remove empty attribute %s from %s?' % (attrname, dn)): + self.report("Not fixing empty attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) + if self.verbose: + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m, controls=["relax:0"], validate=False) + except Exception, msg: + self.report("Failed to remove empty attribute %s : %s" % (attrname, msg)) + return + self.report("Removed empty attribute %s" % attrname) + + + ################################################################ + # handle normalisation mismatches + def err_normalise_mismatch(self, dn, attrname, values): + '''fix attribute normalisation errors''' + self.report("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) + mod_list = [] + for val in values: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, [val]) + if len(normalised) != 1: + self.report("Unable to normalise value '%s'" % val) + mod_list.append((val, '')) + elif (normalised[0] != val): + self.report("value '%s' should be '%s'" % (val, normalised[0])) + mod_list.append((val, normalised[0])) + if not self.confirm('Fix normalisation for %s from %s?' % (attrname, dn)): + self.report("Not fixing attribute %s" % attrname) + return + + m = ldb.Message() + m.dn = dn + for i in range(0, len(mod_list)): + (val, nval) = mod_list[i] + m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + if nval != '': + m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) + + if self.verbose: + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m, controls=["relax:0"], validate=False) + except Exception, msg: + self.report("Failed to normalise attribute %s : %s" % (attrname, msg)) + return + self.report("Normalised attribute %s" % attrname) + + + ################################################################ + # handle a missing GUID extended DN component + def err_incorrect_dn_GUID(self, dn, attrname, val, dsdb_dn, errstr): + self.report("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) + try: + res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, + attrs=[], controls=["extended_dn:1:1"]) + except ldb.LdbError, (enum, estr): + self.report("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) + return + dsdb_dn.dn = res[0].dn + + if not self.confirm('Change DN to %s?' % str(dsdb_dn)): + self.report("Not fixing %s" % errstr) + return + m = ldb.Message() + m.dn = dn + m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) + if self.verbose: + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m) + except Exception, msg: + self.report("Failed to fix %s on attribute %s : %s" % (errstr, attrname, msg)) + return + self.report("Fixed %s on attribute %s" % (errstr, attrname)) + + + ################################################################ + # handle a DN pointing to a deleted object + def err_deleted_dn(self, dn, attrname, val, dsdb_dn, correct_dn): + self.report("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val)) + self.report("Target GUID points at deleted DN %s" % correct_dn) + if not self.confirm('Remove DN?'): + self.report("Not removing") + return + m = ldb.Message() + m.dn = dn + m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + if self.verbose: + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m) + except Exception, msg: + self.report("Failed to remove deleted DN attribute %s : %s" % (attrname, msg)) + return + self.report("Removed deleted DN on attribute %s" % attrname) + + + ################################################################ + # handle a DN string being incorrect + def err_dn_target_mismatch(self, dn, attrname, val, dsdb_dn, correct_dn): + self.report("ERROR: incorrect DN string component for %s in object %s - %s" % (attrname, dn, val)) + dsdb_dn.dn = correct_dn + + if not self.confirm('Change DN to %s?' % str(dsdb_dn)): + self.report("Not fixing %s" % errstr) + return + m = ldb.Message() + m.dn = dn + m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) + m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) + if self.verbose: + self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) + try: + self.samdb.modify(m) + except Exception, msg: + self.report("Failed to fix incorrect DN string on attribute %s : %s" % (attrname, msg)) + return + self.report("Fixed incorrect DN string on attribute %s" % (attrname)) + + + ################################################################ + # specialised checking for a dn attribute + def check_dn(self, obj, attrname, syntax_oid): + '''check a DN attribute for correctness''' + error_count = 0 + for val in obj[attrname]: + dsdb_dn = dsdb_DN(self.samdb, val, syntax_oid) + + # all DNs should have a GUID component + guid = dsdb_dn.dn.get_extended_component("GUID") + if guid is None: + error_count += 1 + self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "missing GUID") + continue + + guidstr = str(misc.GUID(guid)) + + # check its the right GUID + try: + res = self.samdb.search(base="" % guidstr, scope=ldb.SCOPE_BASE, + attrs=['isDeleted'], controls=["extended_dn:1:1", "show_deleted:1"]) + except ldb.LdbError, (enum, estr): + error_count += 1 + self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "incorrect GUID") + continue + + # the target DN might be deleted + if (dsdb_dn.prefix != "B:32:18E2EA80684F11D2B9AA00C04F79F805:" and + 'isDeleted' in res[0] and + res[0]['isDeleted'][0].upper() == "TRUE"): + # note that we don't check this for the special wellKnownObjects prefix + # for Deleted Objects, as we expect that to be deleted + error_count += 1 + self.err_deleted_dn(obj.dn, attrname, val, dsdb_dn, res[0].dn) + continue + + # check the DN matches in string form + if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): + error_count += 1 + self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn) + continue + + return error_count + + + + ################################################################ + # check one object - calls to individual error handlers above + def check_object(self, dn): + '''check one object''' + if self.verbose: + self.report("Checking object %s" % dn) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) + if len(res) != 1: + self.report("Object %s disappeared during check" % dn) + return 1 + obj = res[0] + error_count = 0 + for attrname in obj: + if attrname == 'dn': + continue + + # check for empty attributes + for val in obj[attrname]: + if val == '': + self.err_empty_attribute(dn, attrname) + error_count += 1 + continue + + # get the syntax oid for the attribute, so we can can have + # special handling for some specific attribute types + syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(attrname) + + if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_OR_NAME, + dsdb.DSDB_SYNTAX_STRING_DN, ldb.LDB_SYNTAX_DN ]: + # it's some form of DN, do specialised checking on those + error_count += self.check_dn(obj, attrname, syntax_oid) + + # check for incorrectly normalised attributes + for val in obj[attrname]: + normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, [val]) + if len(normalised) != 1 or normalised[0] != val: + self.err_normalise_mismatch(dn, attrname, obj[attrname]) + error_count += 1 + break + return error_count diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index ccc6355193..4a4fe9cb84 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -20,40 +20,14 @@ import ldb, sys import samba.getopt as options -from samba import dsdb -from samba import common from samba.auth import system_session from samba.samdb import SamDB -from samba.dcerpc import misc from samba.netcmd import ( Command, CommandError, Option ) - - -class dsdb_DN(object): - '''a class to manipulate DN components''' - - def __init__(self, samdb, dnstring, syntax_oid): - if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN ]: - colons = dnstring.split(':') - if len(colons) < 4: - raise Exception("invalid DN prefix") - prefix_len = 4 + len(colons[1]) + int(colons[1]) - self.prefix = dnstring[0:prefix_len] - self.dnstring = dnstring[prefix_len:] - else: - self.dnstring = dnstring - self.prefix = '' - try: - self.dn = ldb.Dn(samdb, self.dnstring) - except Exception, msg: - print("ERROR: bad DN string '%s'" % self.dnstring) - raise - - def __str__(self): - return self.prefix + str(self.dn.extended_str(mode=1)) +from samba.dbchecker import dbcheck class cmd_dbcheck(Command): @@ -86,27 +60,23 @@ class cmd_dbcheck(Command): def run(self, H=None, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, quiet=False, scope="SUB", credopts=None, sambaopts=None, versionopts=None): - self.lp = sambaopts.get_loadparm() - self.creds = credopts.get_credentials(self.lp, fallback_machine=True) - self.samdb = SamDB(session_info=system_session(), url=H, - credentials=self.creds, lp=self.lp) + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp, fallback_machine=True) + + samdb = SamDB(session_info=system_session(), url=H, + credentials=creds, lp=lp) if H is None: - self.local_samdb = self.samdb + samdb_schema = samdb else: - self.local_samdb = SamDB(session_info=system_session(), url=None, - credentials=self.creds, lp=self.lp) - - self.verbose = verbose - self.fix = fix - self.yes = yes - self.quiet = quiet + samdb_schema = SamDB(session_info=system_session(), url=None, + credentials=creds, lp=lp) scope_map = { "SUB": ldb.SCOPE_SUBTREE, "BASE":ldb.SCOPE_BASE, "ONE":ldb.SCOPE_ONELEVEL } scope = scope.upper() if not scope in scope_map: raise CommandError("Unknown scope %s" % scope) - self.search_scope = scope_map[scope] + search_scope = scope_map[scope] controls = [] if H is not None: @@ -114,254 +84,15 @@ class cmd_dbcheck(Command): if cross_ncs: controls.append("search_options:1:2") - if self.yes and self.fix: - self.samdb.transaction_start() + if yes and fix: + samdb.transaction_start() - res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) - self.report('Checking %u objects' % len(res)) - error_count = 0 - for object in res: - error_count += self.check_object(object.dn) - if error_count != 0 and not self.fix: - self.report("Please use --fix to fix these errors") - self.report('Checked %u objects (%u errors)' % (len(res), error_count)) + chk = dbcheck(samdb, samdb_schema=samdb_schema, verbose=verbose, fix=fix, yes=yes, quiet=quiet) + error_count = chk.check_database(DN=DN, scope=search_scope, controls=controls) - if self.yes and self.fix: - self.samdb.transaction_commit() + if yes and fix: + samdb.transaction_commit() if error_count != 0: sys.exit(1) - - def report(self, msg): - '''print a message unless quiet is set''' - if not self.quiet: - print(msg) - - - ################################################################ - # a local confirm function that obeys the --fix and --yes options - def confirm(self, msg): - '''confirm a change''' - if not self.fix: - return False - return common.confirm(msg, forced=self.yes) - - - ################################################################ - # handle empty attributes - def err_empty_attribute(self, dn, attrname): - '''fix empty attributes''' - self.report("ERROR: Empty attribute %s in %s" % (attrname, dn)) - if not self.confirm('Remove empty attribute %s from %s?' % (attrname, dn)): - self.report("Not fixing empty attribute %s" % attrname) - return - - m = ldb.Message() - m.dn = dn - m[attrname] = ldb.MessageElement('', ldb.FLAG_MOD_DELETE, attrname) - if self.verbose: - self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) - try: - self.samdb.modify(m, controls=["relax:0"], validate=False) - except Exception, msg: - self.report("Failed to remove empty attribute %s : %s" % (attrname, msg)) - return - self.report("Removed empty attribute %s" % attrname) - - - ################################################################ - # handle normalisation mismatches - def err_normalise_mismatch(self, dn, attrname, values): - '''fix attribute normalisation errors''' - self.report("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn)) - mod_list = [] - for val in values: - normalised = self.samdb.dsdb_normalise_attributes(self.local_samdb, attrname, [val]) - if len(normalised) != 1: - self.report("Unable to normalise value '%s'" % val) - mod_list.append((val, '')) - elif (normalised[0] != val): - self.report("value '%s' should be '%s'" % (val, normalised[0])) - mod_list.append((val, normalised[0])) - if not self.confirm('Fix normalisation for %s from %s?' % (attrname, dn)): - self.report("Not fixing attribute %s" % attrname) - return - - m = ldb.Message() - m.dn = dn - for i in range(0, len(mod_list)): - (val, nval) = mod_list[i] - m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) - if nval != '': - m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname) - - if self.verbose: - self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) - try: - self.samdb.modify(m, controls=["relax:0"], validate=False) - except Exception, msg: - self.report("Failed to normalise attribute %s : %s" % (attrname, msg)) - return - self.report("Normalised attribute %s" % attrname) - - - ################################################################ - # handle a missing GUID extended DN component - def err_incorrect_dn_GUID(self, dn, attrname, val, dsdb_dn, errstr): - self.report("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) - try: - res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, - attrs=[], controls=["extended_dn:1:1"]) - except ldb.LdbError, (enum, estr): - self.report("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) - return - dsdb_dn.dn = res[0].dn - - if not self.confirm('Change DN to %s?' % str(dsdb_dn)): - self.report("Not fixing %s" % errstr) - return - m = ldb.Message() - m.dn = dn - m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) - m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) - if self.verbose: - self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) - try: - self.samdb.modify(m) - except Exception, msg: - self.report("Failed to fix %s on attribute %s : %s" % (errstr, attrname, msg)) - return - self.report("Fixed %s on attribute %s" % (errstr, attrname)) - - - ################################################################ - # handle a DN pointing to a deleted object - def err_deleted_dn(self, dn, attrname, val, dsdb_dn, correct_dn): - self.report("ERROR: target DN is deleted for %s in object %s - %s" % (attrname, dn, val)) - self.report("Target GUID points at deleted DN %s" % correct_dn) - if not self.confirm('Remove DN?'): - self.report("Not removing") - return - m = ldb.Message() - m.dn = dn - m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) - if self.verbose: - self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) - try: - self.samdb.modify(m) - except Exception, msg: - self.report("Failed to remove deleted DN attribute %s : %s" % (attrname, msg)) - return - self.report("Removed deleted DN on attribute %s" % attrname) - - - ################################################################ - # handle a DN string being incorrect - def err_dn_target_mismatch(self, dn, attrname, val, dsdb_dn, correct_dn): - self.report("ERROR: incorrect DN string component for %s in object %s - %s" % (attrname, dn, val)) - dsdb_dn.dn = correct_dn - - if not self.confirm('Change DN to %s?' % str(dsdb_dn)): - self.report("Not fixing %s" % errstr) - return - m = ldb.Message() - m.dn = dn - m['old_value'] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname) - m['new_value'] = ldb.MessageElement(str(dsdb_dn), ldb.FLAG_MOD_ADD, attrname) - if self.verbose: - self.report(self.samdb.write_ldif(m, ldb.CHANGETYPE_MODIFY)) - try: - self.samdb.modify(m) - except Exception, msg: - self.report("Failed to fix incorrect DN string on attribute %s : %s" % (attrname, msg)) - return - self.report("Fixed incorrect DN string on attribute %s" % (attrname)) - - - ################################################################ - # specialised checking for a dn attribute - def check_dn(self, obj, attrname, syntax_oid): - '''check a DN attribute for correctness''' - error_count = 0 - for val in obj[attrname]: - dsdb_dn = dsdb_DN(self.samdb, val, syntax_oid) - - # all DNs should have a GUID component - guid = dsdb_dn.dn.get_extended_component("GUID") - if guid is None: - error_count += 1 - self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "missing GUID") - continue - - guidstr = str(misc.GUID(guid)) - - # check its the right GUID - try: - res = self.samdb.search(base="" % guidstr, scope=ldb.SCOPE_BASE, - attrs=['isDeleted'], controls=["extended_dn:1:1", "show_deleted:1"]) - except ldb.LdbError, (enum, estr): - error_count += 1 - self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "incorrect GUID") - continue - - # the target DN might be deleted - if (dsdb_dn.prefix != "B:32:18E2EA80684F11D2B9AA00C04F79F805:" and - 'isDeleted' in res[0] and - res[0]['isDeleted'][0].upper() == "TRUE"): - # note that we don't check this for the special wellKnownObjects prefix - # for Deleted Objects, as we expect that to be deleted - error_count += 1 - self.err_deleted_dn(obj.dn, attrname, val, dsdb_dn, res[0].dn) - continue - - # check the DN matches in string form - if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): - error_count += 1 - self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn) - continue - - return error_count - - - - ################################################################ - # check one object - calls to individual error handlers above - def check_object(self, dn): - '''check one object''' - if self.verbose: - self.report("Checking object %s" % dn) - res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) - if len(res) != 1: - self.report("Object %s disappeared during check" % dn) - return 1 - obj = res[0] - error_count = 0 - for attrname in obj: - if attrname == 'dn': - continue - - # check for empty attributes - for val in obj[attrname]: - if val == '': - self.err_empty_attribute(dn, attrname) - error_count += 1 - continue - - # get the syntax oid for the attribute, so we can can have - # special handling for some specific attribute types - syntax_oid = self.local_samdb.get_syntax_oid_from_lDAPDisplayName(attrname) - - if syntax_oid in [ dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_OR_NAME, - dsdb.DSDB_SYNTAX_STRING_DN, ldb.LDB_SYNTAX_DN ]: - # it's some form of DN, do specialised checking on those - error_count += self.check_dn(obj, attrname, syntax_oid) - - # check for incorrectly normalised attributes - for val in obj[attrname]: - normalised = self.samdb.dsdb_normalise_attributes(self.local_samdb, attrname, [val]) - if len(normalised) != 1 or normalised[0] != val: - self.err_normalise_mismatch(dn, attrname, obj[attrname]) - error_count += 1 - break - return error_count -- cgit From 9676c26fdd7ca53405abd06f58ae40d39d818e4d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 20:44:35 +1000 Subject: samba-tool: added --attrs option to dbcheck this allows checking of a specific list of attributes --- source4/scripting/python/samba/dbchecker.py | 13 +++++++------ source4/scripting/python/samba/netcmd/dbcheck.py | 10 ++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py index 1687c82d83..38c3549245 100644 --- a/source4/scripting/python/samba/dbchecker.py +++ b/source4/scripting/python/samba/dbchecker.py @@ -58,15 +58,14 @@ class dbcheck(object): self.yes = yes self.quiet = quiet - def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=[]): + def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=[], attrs=['*']): '''perform a database check, returning the number of errors found''' - self.search_scope = scope - res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls) + res = self.samdb.search(base=DN, scope=scope, attrs=['dn'], controls=controls) self.report('Checking %u objects' % len(res)) error_count = 0 for object in res: - error_count += self.check_object(object.dn) + error_count += self.check_object(object.dn, attrs=attrs) if error_count != 0 and not self.fix: self.report("Please use --fix to fix these errors") self.report('Checked %u objects (%u errors)' % (len(res), error_count)) @@ -86,6 +85,8 @@ class dbcheck(object): '''confirm a change''' if not self.fix: return False + if self.quiet: + return self.yes return common.confirm(msg, forced=self.yes) @@ -268,11 +269,11 @@ class dbcheck(object): ################################################################ # check one object - calls to individual error handlers above - def check_object(self, dn): + def check_object(self, dn, attrs=['*']): '''check one object''' if self.verbose: self.report("Checking object %s" % dn) - res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor']) + res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=attrs) if len(res) != 1: self.report("Object %s disappeared during check" % dn) return 1 diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index 4a4fe9cb84..b8a0055d3a 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -55,11 +55,12 @@ class cmd_dbcheck(Command): help="Print more details of checking"), Option("--quiet", dest="quiet", action="store_true", default=False, help="don't print details of checking"), + Option("--attrs", dest="attrs", default=None, help="list of attributes to check (space separated)"), Option("-H", help="LDB URL for database or target server (defaults to local SAM database)", type=str), ] def run(self, H=None, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, quiet=False, - scope="SUB", credopts=None, sambaopts=None, versionopts=None): + scope="SUB", credopts=None, sambaopts=None, versionopts=None, attrs=None): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) @@ -84,11 +85,16 @@ class cmd_dbcheck(Command): if cross_ncs: controls.append("search_options:1:2") + if not attrs: + attrs = ['*'] + else: + attrs = attrs.split() + if yes and fix: samdb.transaction_start() chk = dbcheck(samdb, samdb_schema=samdb_schema, verbose=verbose, fix=fix, yes=yes, quiet=quiet) - error_count = chk.check_database(DN=DN, scope=search_scope, controls=controls) + error_count = chk.check_database(DN=DN, scope=search_scope, controls=controls, attrs=attrs) if yes and fix: samdb.transaction_commit() -- cgit From 6b939f4a9c19cd868ac1b6d77cc26662e2726e8c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 20:53:44 +1000 Subject: dbchecker: when fixing a bad GUID in a DN, search by the string DN --- source4/scripting/python/samba/dbchecker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py index 38c3549245..2594e9a1fe 100644 --- a/source4/scripting/python/samba/dbchecker.py +++ b/source4/scripting/python/samba/dbchecker.py @@ -153,7 +153,7 @@ class dbcheck(object): def err_incorrect_dn_GUID(self, dn, attrname, val, dsdb_dn, errstr): self.report("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) try: - res = self.samdb.search(base=dsdb_dn.dn, scope=ldb.SCOPE_BASE, + res = self.samdb.search(base=str(dsdb_dn.dn), scope=ldb.SCOPE_BASE, attrs=[], controls=["extended_dn:1:1"]) except ldb.LdbError, (enum, estr): self.report("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) -- cgit From 4fe9ebc2e3e09befe8d7a2ce577336eefd9b9694 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 21:22:39 +1000 Subject: dbchecker: fixed argument error for -H and DN --- source4/scripting/python/samba/netcmd/dbcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py index b8a0055d3a..3cc50eb814 100644 --- a/source4/scripting/python/samba/netcmd/dbcheck.py +++ b/source4/scripting/python/samba/netcmd/dbcheck.py @@ -59,7 +59,7 @@ class cmd_dbcheck(Command): Option("-H", help="LDB URL for database or target server (defaults to local SAM database)", type=str), ] - def run(self, H=None, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False, quiet=False, + def run(self, DN=None, H=None, verbose=False, fix=False, yes=False, cross_ncs=False, quiet=False, scope="SUB", credopts=None, sambaopts=None, versionopts=None, attrs=None): lp = sambaopts.get_loadparm() -- cgit From 2f4251c389f5fa92bfba10739677a760f0bdf198 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 22 Jun 2011 22:06:18 +1000 Subject: dbchecker: cope with a broken link to Deleted Objects if a DN link to Deleted Objects has a bad GUID, we need to use show_deleted --- source4/scripting/python/samba/dbchecker.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py index 2594e9a1fe..d7680eda94 100644 --- a/source4/scripting/python/samba/dbchecker.py +++ b/source4/scripting/python/samba/dbchecker.py @@ -147,14 +147,21 @@ class dbcheck(object): return self.report("Normalised attribute %s" % attrname) + def is_deleted_objects_dn(self, dsdb_dn): + '''see if a dsdb_DN is the special Deleted Objects DN''' + return dsdb_dn.prefix == "B:32:18E2EA80684F11D2B9AA00C04F79F805:" + ################################################################ # handle a missing GUID extended DN component def err_incorrect_dn_GUID(self, dn, attrname, val, dsdb_dn, errstr): self.report("ERROR: %s component for %s in object %s - %s" % (errstr, attrname, dn, val)) + controls=["extended_dn:1:1"] + if self.is_deleted_objects_dn(dsdb_dn): + controls.append("show_deleted:1") try: res = self.samdb.search(base=str(dsdb_dn.dn), scope=ldb.SCOPE_BASE, - attrs=[], controls=["extended_dn:1:1"]) + attrs=[], controls=controls) except ldb.LdbError, (enum, estr): self.report("unable to find object for DN %s - cannot fix (%s)" % (dsdb_dn.dn, estr)) return @@ -248,7 +255,7 @@ class dbcheck(object): continue # the target DN might be deleted - if (dsdb_dn.prefix != "B:32:18E2EA80684F11D2B9AA00C04F79F805:" and + if ((not self.is_deleted_objects_dn(dsdb_dn)) and 'isDeleted' in res[0] and res[0]['isDeleted'][0].upper() == "TRUE"): # note that we don't check this for the special wellKnownObjects prefix -- cgit From c2dfaa2580918cf31069c1063ff07a819ca0554a Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 21 Jun 2011 13:37:26 +0400 Subject: s4-upgradeprovision: Don't forget to populate the non replicated objects, and don't touch rIDPreviousAllocationPool --- source4/scripting/bin/upgradeprovision | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index f10a9fcc9c..e98b642776 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -93,7 +93,7 @@ replAttrNotCopied = [ "dn", "whenCreated", "whenChanged", "objectGUID", "sAMAccountType", "oEMInformation", "creationTime" ] nonreplAttrNotCopied = ["uSNCreated", "replPropertyMetaData", "uSNChanged", - "nextRid" ,"rIDNextRID"] + "nextRid" ,"rIDNextRID", "rIDPreviousAllocationPool"] nonDSDBAttrNotCopied = ["msDS-KeyVersionNumber", "priorSecret", "priorWhenChanged"] @@ -266,7 +266,8 @@ def populateNotReplicated(samdb, schemadn): str(schemadn)), scope=SCOPE_SUBTREE, attrs=["lDAPDisplayName"]) for elem in res: - not_replicated.append(elem["lDAPDisplayName"]) + not_replicated.append(str(elem["lDAPDisplayName"])) + def populate_dnsyntax(samdb, schemadn): """Populate an array with all the attributes that have DN synthax @@ -1778,6 +1779,7 @@ if __name__ == '__main__': new_ldbs = get_ldbs(newpaths, creds, session, lp) new_ldbs.startTransactions() + populateNotReplicated(new_ldbs.sam, names.schemadn) # 8) Populate some associative array to ease the update process # List of attribute which are link and backlink populate_links(new_ldbs.sam, names.schemadn) -- cgit From 249fbd8a334b4d19f9148e07449fec3f26b8267d Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 21 Jun 2011 13:39:28 +0400 Subject: s4-samba_dnsupdate: set environment via the env parameter I faced a situation where the os.environ("KRB5CCNAME") = ... didn't seems to be effective --- source4/scripting/bin/samba_dnsupdate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate index 0a13dd7c9b..78d7dc1712 100755 --- a/source4/scripting/bin/samba_dnsupdate +++ b/source4/scripting/bin/samba_dnsupdate @@ -278,7 +278,7 @@ def call_nsupdate(d): try: cmd = nsupdate_cmd[:] cmd.append(tmpfile) - ret = subprocess.call(cmd, shell=False) + ret = subprocess.call(cmd, shell=False, env={"KRB5CCNAME": ccachename}) if ret != 0: if opts.fail_immediately: sys.exit(1) -- cgit From ef7940f7be7de238a693cfba649faf8b67b7da3a Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Wed, 22 Jun 2011 21:28:00 +0400 Subject: s4-dbcheck: remove unused include --- source4/scripting/python/samba/dbchecker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py index d7680eda94..dd76cd878d 100644 --- a/source4/scripting/python/samba/dbchecker.py +++ b/source4/scripting/python/samba/dbchecker.py @@ -18,7 +18,7 @@ # along with this program. If not, see . # -import ldb, sys +import ldb from samba import dsdb from samba import common from samba.dcerpc import misc -- cgit From a9e45923369e3171cb7f42284f52ce3c4c8b0a4b Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Wed, 22 Jun 2011 21:28:25 +0400 Subject: s4-dbcheck: fix uninitialized errstr in err_dn_target_mismatch Autobuild-User: Matthieu Patou Autobuild-Date: Wed Jun 22 21:22:27 CEST 2011 on sn-devel-104 --- source4/scripting/python/samba/dbchecker.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source4/scripting') diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py index dd76cd878d..88fd0edf00 100644 --- a/source4/scripting/python/samba/dbchecker.py +++ b/source4/scripting/python/samba/dbchecker.py @@ -207,7 +207,7 @@ class dbcheck(object): ################################################################ # handle a DN string being incorrect - def err_dn_target_mismatch(self, dn, attrname, val, dsdb_dn, correct_dn): + def err_dn_target_mismatch(self, dn, attrname, val, dsdb_dn, correct_dn, errstr): self.report("ERROR: incorrect DN string component for %s in object %s - %s" % (attrname, dn, val)) dsdb_dn.dn = correct_dn @@ -267,7 +267,8 @@ class dbcheck(object): # check the DN matches in string form if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): error_count += 1 - self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn) + self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, + res[0].dn, "incorrect string version of DN") continue return error_count -- cgit