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/python/samba/netcmd') 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 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/python/samba/netcmd') 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 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/python/samba/netcmd') 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/python/samba/netcmd') 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 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba/netcmd') 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""" -- 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 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source4/scripting/python/samba/netcmd') 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]""" -- 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/python/samba/netcmd') 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 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/python/samba/netcmd') 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/python/samba/netcmd') 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/python/samba/netcmd') 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 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/python/samba/netcmd') 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/python/samba/netcmd') 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 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/python/samba/netcmd') 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/python/samba/netcmd') 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 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/python/samba/netcmd') 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/python/samba/netcmd') 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/python/samba/netcmd') 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/netcmd/dbcheck.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'source4/scripting/python/samba/netcmd') 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 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/python/samba/netcmd') 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 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/python/samba/netcmd') 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/python/samba/netcmd') 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/python/samba/netcmd') 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/python/samba/netcmd') 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/netcmd/dbcheck.py | 301 ++--------------------- 1 file changed, 16 insertions(+), 285 deletions(-) (limited to 'source4/scripting/python/samba/netcmd') 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/netcmd/dbcheck.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'source4/scripting/python/samba/netcmd') 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 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/python/samba/netcmd') 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