2011-06-10 17:17:12 +10:00
# 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 <http://www.gnu.org/licenses/>.
#
2011-06-19 21:27:32 +04:00
import ldb , sys
2011-06-10 17:17:12 +10:00
import samba . getopt as options
from samba . auth import system_session
from samba . samdb import SamDB
from samba . netcmd import (
Command ,
CommandError ,
Option
)
2011-06-22 20:01:58 +10:00
from samba . dbchecker import dbcheck
2011-06-22 14:44:36 +10:00
2011-06-10 17:17:12 +10:00
class cmd_dbcheck ( Command ) :
2012-10-08 12:32:58 +02:00
""" Check local AD database for errors. """
2011-10-13 23:27:22 +02:00
synopsis = " % prog [<DN>] [options] "
2011-06-10 17:17:12 +10:00
2012-02-06 16:33:38 +01:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptionsDouble ,
}
2011-06-10 17:17:12 +10:00
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 ' ,
2011-06-22 17:08:28 +10:00
help = " don ' t confirm changes, just do them all as a single transaction " ) ,
2011-06-17 11:31:25 +10:00
Option ( " --cross-ncs " , dest = " cross_ncs " , default = False , action = ' store_true ' ,
help = " cross naming context boundaries " ) ,
2011-06-10 17:17:12 +10:00
Option ( " -v " , " --verbose " , dest = " verbose " , action = " store_true " , default = False ,
help = " Print more details of checking " ) ,
2011-06-22 19:32:45 +10:00
Option ( " --quiet " , dest = " quiet " , action = " store_true " , default = False ,
help = " don ' t print details of checking " ) ,
2011-06-22 20:44:35 +10:00
Option ( " --attrs " , dest = " attrs " , default = None , help = " list of attributes to check (space separated) " ) ,
2011-07-12 11:05:43 +10:00
Option ( " --reindex " , dest = " reindex " , default = False , action = " store_true " , help = " force database re-index " ) ,
2012-08-23 15:18:13 +10:00
Option ( " --force-modules " , dest = " force_modules " , default = False , action = " store_true " , help = " force loading of Samba modules and ignore the @MODULES record (for very old databases) " ) ,
2013-02-11 14:49:01 +11:00
Option ( " --reset-well-known-acls " , dest = " reset_well_known_acls " , default = False , action = " store_true " , help = " reset ACLs on objects with well known default ACL values to the default " ) ,
2011-07-25 11:56:10 -04:00
Option ( " -H " , " --URL " , help = " LDB URL for database or target server (defaults to local SAM database) " ,
type = str , metavar = " URL " , dest = " H " ) ,
2011-06-10 17:17:12 +10:00
]
2011-10-13 00:36:44 +02:00
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 ,
2013-02-11 14:49:01 +11:00
attrs = None , reindex = False , force_modules = False ,
reset_well_known_acls = False ) :
2011-06-10 17:17:12 +10:00
2011-06-22 20:01:58 +10:00
lp = sambaopts . get_loadparm ( )
2011-07-11 10:53:52 +10:00
over_ldap = H is not None and H . startswith ( ' ldap ' )
if over_ldap :
creds = credopts . get_credentials ( lp , fallback_machine = True )
else :
creds = None
2011-06-22 20:01:58 +10:00
2012-08-23 15:18:13 +10:00
if force_modules :
samdb = SamDB ( session_info = system_session ( ) , url = H ,
credentials = creds , lp = lp , options = [ " modules=samba_dsdb " ] )
else :
try :
samdb = SamDB ( session_info = system_session ( ) , url = H ,
credentials = creds , lp = lp )
except :
raise CommandError ( " Failed to connect to DB at %s . If this is a really old sam.ldb (before alpha9), then try again with --force-modules " % H )
2011-07-11 10:53:52 +10:00
if H is None or not over_ldap :
2011-06-22 20:01:58 +10:00
samdb_schema = samdb
2011-06-22 17:38:19 +10:00
else :
2011-06-22 20:01:58 +10:00
samdb_schema = SamDB ( session_info = system_session ( ) , url = None ,
credentials = creds , lp = lp )
2011-06-10 17:17:12 +10:00
2011-10-13 00:36:44 +02:00
scope_map = { " SUB " : ldb . SCOPE_SUBTREE , " BASE " : ldb . SCOPE_BASE , " ONE " : ldb . SCOPE_ONELEVEL }
2011-06-10 17:17:12 +10:00
scope = scope . upper ( )
if not scope in scope_map :
raise CommandError ( " Unknown scope %s " % scope )
2011-06-22 20:01:58 +10:00
search_scope = scope_map [ scope ]
2011-06-10 17:17:12 +10:00
2011-07-11 12:23:01 +10:00
controls = [ ' show_deleted:1 ' ]
2011-07-12 11:12:21 +10:00
if over_ldap :
2011-06-22 17:38:19 +10:00
controls . append ( ' paged_results:1:1000 ' )
2011-06-17 11:31:25 +10:00
if cross_ncs :
controls . append ( " search_options:1:2 " )
2011-06-22 20:44:35 +10:00
if not attrs :
attrs = [ ' * ' ]
else :
attrs = attrs . split ( )
2011-09-22 09:58:39 +10:00
started_transaction = False
2011-06-22 20:01:58 +10:00
if yes and fix :
samdb . transaction_start ( )
2011-09-22 09:58:39 +10:00
started_transaction = True
2011-08-01 20:04:02 +02:00
try :
chk = dbcheck ( samdb , samdb_schema = samdb_schema , verbose = verbose ,
2013-02-11 14:49:01 +11:00
fix = fix , yes = yes , quiet = quiet , in_transaction = started_transaction ,
reset_well_known_acls = reset_well_known_acls )
2011-08-01 20:04:02 +02:00
if reindex :
2011-10-13 00:36:44 +02:00
self . outf . write ( " Re-indexing... \n " )
2011-08-01 20:04:02 +02:00
error_count = 0
if chk . reindex_database ( ) :
2011-10-13 00:36:44 +02:00
self . outf . write ( " completed re-index OK \n " )
2012-08-23 15:18:13 +10:00
elif force_modules :
self . outf . write ( " Resetting @MODULES... \n " )
error_count = 0
if chk . reset_modules ( ) :
self . outf . write ( " completed @MODULES reset OK \n " )
2011-08-01 20:04:02 +02:00
else :
error_count = chk . check_database ( DN = DN , scope = search_scope ,
controls = controls , attrs = attrs )
2012-02-25 15:56:25 +01:00
except :
2011-09-22 09:58:39 +10:00
if started_transaction :
samdb . transaction_cancel ( )
2011-08-01 20:04:02 +02:00
raise
2011-06-22 17:08:28 +10:00
2011-09-22 09:58:39 +10:00
if started_transaction :
2011-06-22 20:01:58 +10:00
samdb . transaction_commit ( )
2011-06-22 17:08:28 +10:00
2011-06-17 14:40:48 +10:00
if error_count != 0 :
sys . exit ( 1 )