2011-06-22 14:01:58 +04:00
# Samba4 AD database checker
#
# Copyright (C) Andrew Tridgell 2011
2011-07-07 00:31:21 +04:00
# Copyright (C) Matthieu Patou <mat@matws.net> 2011
2011-06-22 14:01:58 +04:00
#
# 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-22 21:28:00 +04:00
import ldb
2011-06-22 14:01:58 +04:00
from samba import dsdb
from samba import common
from samba . dcerpc import misc
2013-01-19 12:41:00 +04:00
from samba . ndr import ndr_unpack , ndr_pack
2011-07-07 00:31:21 +04:00
from samba . dcerpc import drsblobs
2011-10-20 06:24:45 +04:00
from samba . common import dsdb_Dn
2013-01-19 12:41:00 +04:00
from samba . dcerpc import security
2011-06-22 14:01:58 +04:00
2012-02-19 02:59:48 +04:00
2011-06-22 14:01:58 +04:00
class dbcheck ( object ) :
""" check a SAM database for errors """
2012-02-19 02:59:48 +04:00
def __init__ ( self , samdb , samdb_schema = None , verbose = False , fix = False ,
yes = False , quiet = False , in_transaction = False ) :
2011-06-22 14:01:58 +04:00
self . samdb = samdb
2011-07-07 00:31:21 +04:00
self . dict_oid_name = None
2011-06-22 14:01:58 +04:00
self . samdb_schema = ( samdb_schema or samdb )
self . verbose = verbose
self . fix = fix
self . yes = yes
self . quiet = quiet
2011-07-05 06:42:53 +04:00
self . remove_all_unknown_attributes = False
2011-07-11 05:09:00 +04:00
self . remove_all_empty_attributes = False
self . fix_all_normalisation = False
self . fix_all_DN_GUIDs = False
2013-02-11 01:25:41 +04:00
self . fix_all_binary_dn = False
2011-07-11 05:09:00 +04:00
self . remove_all_deleted_DN_links = False
self . fix_all_target_mismatch = False
2011-07-11 08:05:30 +04:00
self . fix_all_metadata = False
2011-11-13 17:09:24 +04:00
self . fix_time_metadata = False
2011-07-11 10:55:36 +04:00
self . fix_all_missing_backlinks = False
self . fix_all_orphaned_backlinks = False
2012-04-18 09:46:14 +04:00
self . fix_rmd_flags = False
2013-01-19 12:41:00 +04:00
self . fix_ntsecuritydescriptor = False
2012-04-19 08:14:35 +04:00
self . seize_fsmo_role = False
2012-07-06 13:59:09 +04:00
self . move_to_lost_and_found = False
2012-07-17 05:10:41 +04:00
self . fix_instancetype = False
2011-12-08 04:47:59 +04:00
self . in_transaction = in_transaction
2012-04-19 08:14:35 +04:00
self . infrastructure_dn = ldb . Dn ( samdb , " CN=Infrastructure, " + samdb . domain_dn ( ) )
self . naming_dn = ldb . Dn ( samdb , " CN=Partitions, %s " % samdb . get_config_basedn ( ) )
self . schema_dn = samdb . get_schema_basedn ( )
self . rid_dn = ldb . Dn ( samdb , " CN=RID Manager$,CN=System, " + samdb . domain_dn ( ) )
2013-02-11 01:25:41 +04:00
self . ntds_dsa = ldb . Dn ( samdb , samdb . get_dsServiceName ( ) )
2013-01-19 12:41:00 +04:00
self . class_schemaIDGUID = { }
2012-07-17 05:10:41 +04:00
2012-10-24 09:09:20 +04:00
res = self . samdb . search ( base = self . ntds_dsa , scope = ldb . SCOPE_BASE , attrs = [ ' msDS-hasMasterNCs ' , ' hasMasterNCs ' ] )
2012-07-17 05:10:41 +04:00
if " msDS-hasMasterNCs " in res [ 0 ] :
self . write_ncs = res [ 0 ] [ " msDS-hasMasterNCs " ]
else :
2012-10-24 09:09:20 +04:00
# If the Forest Level is less than 2003 then there is no
# msDS-hasMasterNCs, so we fall back to hasMasterNCs
# no need to merge as all the NCs that are in hasMasterNCs must
# also be in msDS-hasMasterNCs (but not the opposite)
if " hasMasterNCs " in res [ 0 ] :
self . write_ncs = res [ 0 ] [ " hasMasterNCs " ]
else :
self . write_ncs = None
2011-06-22 14:01:58 +04:00
2011-06-22 14:44:35 +04:00
def check_database ( self , DN = None , scope = ldb . SCOPE_SUBTREE , controls = [ ] , attrs = [ ' * ' ] ) :
2011-06-22 14:01:58 +04:00
''' perform a database check, returning the number of errors found '''
2011-06-22 14:44:35 +04:00
res = self . samdb . search ( base = DN , scope = scope , attrs = [ ' dn ' ] , controls = controls )
2011-06-22 14:01:58 +04:00
self . report ( ' Checking %u objects ' % len ( res ) )
error_count = 0
2011-08-11 10:59:11 +04:00
2011-06-22 14:01:58 +04:00
for object in res :
2011-06-22 14:44:35 +04:00
error_count + = self . check_object ( object . dn , attrs = attrs )
2011-08-11 10:59:11 +04:00
if DN is None :
error_count + = self . check_rootdse ( )
2011-06-22 14:01:58 +04:00
if error_count != 0 and not self . fix :
self . report ( " Please use --fix to fix these errors " )
2011-08-11 10:59:11 +04:00
2011-06-22 14:01:58 +04:00
self . report ( ' Checked %u objects ( %u errors) ' % ( len ( res ) , error_count ) )
return error_count
def report ( self , msg ) :
''' print a message unless quiet is set '''
if not self . quiet :
print ( msg )
2011-07-05 06:42:53 +04:00
def confirm ( self , msg , allow_all = False , forced = False ) :
2011-06-22 14:01:58 +04:00
''' confirm a change '''
if not self . fix :
return False
2011-06-22 14:44:35 +04:00
if self . quiet :
return self . yes
2011-07-05 06:42:53 +04:00
if self . yes :
forced = True
return common . confirm ( msg , forced = forced , allow_all = allow_all )
################################################################
# a local confirm function with support for 'all'
def confirm_all ( self , msg , all_attr ) :
''' confirm a change with support for " all " '''
if not self . fix :
return False
if self . quiet :
return self . yes
2011-07-05 07:03:18 +04:00
if getattr ( self , all_attr ) == ' NONE ' :
return False
if getattr ( self , all_attr ) == ' ALL ' :
forced = True
else :
forced = self . yes
2011-07-05 06:42:53 +04:00
c = common . confirm ( msg , forced = forced , allow_all = True )
if c == ' ALL ' :
2011-07-05 07:03:18 +04:00
setattr ( self , all_attr , ' ALL ' )
return True
if c == ' NONE ' :
setattr ( self , all_attr , ' NONE ' )
2012-05-24 22:43:17 +04:00
return False
2011-07-05 06:42:53 +04:00
return c
2011-06-22 14:01:58 +04:00
2011-07-11 10:55:36 +04:00
def do_modify ( self , m , controls , msg , validate = True ) :
''' perform a modify with optional verbose output '''
if self . verbose :
self . report ( self . samdb . write_ldif ( m , ldb . CHANGETYPE_MODIFY ) )
try :
2012-06-16 05:51:22 +04:00
controls = controls + [ " local_oid: %s :0 " % dsdb . DSDB_CONTROL_DBCHECK ]
2011-07-11 10:55:36 +04:00
self . samdb . modify ( m , controls = controls , validate = validate )
except Exception , err :
self . report ( " %s : %s " % ( msg , err ) )
return False
return True
2012-07-06 13:59:09 +04:00
def do_rename ( self , from_dn , to_rdn , to_base , controls , msg ) :
''' perform a modify with optional verbose output '''
if self . verbose :
self . report ( """ dn: %s
changeType : modrdn
newrdn : % s
deleteOldRdn : 1
newSuperior : % s """ % (str(from_dn), str(to_rdn), str(to_base)))
try :
to_dn = to_rdn + to_base
controls = controls + [ " local_oid: %s :0 " % dsdb . DSDB_CONTROL_DBCHECK ]
self . samdb . rename ( from_dn , to_dn , controls = controls )
except Exception , err :
self . report ( " %s : %s " % ( msg , err ) )
return False
return True
2011-06-22 14:01:58 +04:00
def err_empty_attribute ( self , dn , attrname ) :
''' fix empty attributes '''
self . report ( " ERROR: Empty attribute %s in %s " % ( attrname , dn ) )
2011-07-11 05:09:00 +04:00
if not self . confirm_all ( ' Remove empty attribute %s from %s ? ' % ( attrname , dn ) , ' remove_all_empty_attributes ' ) :
2011-06-22 14:01:58 +04:00
self . report ( " Not fixing empty attribute %s " % attrname )
return
m = ldb . Message ( )
m . dn = dn
m [ attrname ] = ldb . MessageElement ( ' ' , ldb . FLAG_MOD_DELETE , attrname )
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " relax:0 " , " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to remove empty attribute %s " % attrname , validate = False ) :
self . report ( " Removed empty attribute %s " % attrname )
2011-06-22 14:01:58 +04:00
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 :
2012-02-19 02:59:48 +04:00
normalised = self . samdb . dsdb_normalise_attributes (
self . samdb_schema , attrname , [ val ] )
2011-06-22 14:01:58 +04:00
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 ] ) )
2011-07-11 05:09:00 +04:00
if not self . confirm_all ( ' Fix normalisation for %s from %s ? ' % ( attrname , dn ) , ' fix_all_normalisation ' ) :
2011-06-22 14:01:58 +04:00
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 != ' ' :
2012-02-19 02:59:48 +04:00
m [ ' normv_ %u ' % i ] = ldb . MessageElement ( nval , ldb . FLAG_MOD_ADD ,
attrname )
2011-06-22 14:01:58 +04:00
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " relax:0 " , " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to normalise attribute %s " % attrname ,
validate = False ) :
self . report ( " Normalised attribute %s " % attrname )
2011-06-22 14:01:58 +04:00
2012-04-11 19:18:37 +04:00
def err_normalise_mismatch_replace ( self , dn , attrname , values ) :
''' fix attribute normalisation errors '''
normalised = self . samdb . dsdb_normalise_attributes ( self . samdb_schema , attrname , values )
self . report ( " ERROR: Normalisation error for attribute ' %s ' in ' %s ' " % ( attrname , dn ) )
self . report ( " Values/Order of values do/does not match: %s / %s ! " % ( values , list ( normalised ) ) )
if list ( normalised ) == values :
return
if not self . confirm_all ( " Fix normalisation for ' %s ' from ' %s ' ? " % ( attrname , dn ) , ' fix_all_normalisation ' ) :
self . report ( " Not fixing attribute ' %s ' " % attrname )
return
m = ldb . Message ( )
m . dn = dn
m [ attrname ] = ldb . MessageElement ( normalised , ldb . FLAG_MOD_REPLACE , attrname )
if self . do_modify ( m , [ " relax:0 " , " show_recycled:1 " ] ,
" Failed to normalise attribute %s " % attrname ,
validate = False ) :
self . report ( " Normalised attribute %s " % attrname )
2011-06-22 16:06:18 +04:00
def is_deleted_objects_dn ( self , dsdb_dn ) :
2011-10-20 06:24:45 +04:00
''' see if a dsdb_Dn is the special Deleted Objects DN '''
2011-06-22 16:06:18 +04:00
return dsdb_dn . prefix == " B:32:18E2EA80684F11D2B9AA00C04F79F805: "
2011-10-06 07:21:41 +04:00
def err_deleted_dn ( self , dn , attrname , val , dsdb_dn , correct_dn ) :
2012-02-19 02:59:48 +04:00
""" handle a DN pointing to a deleted object """
2011-10-06 07:21:41 +04:00
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_all ( ' Remove DN link? ' , ' remove_all_deleted_DN_links ' ) :
self . report ( " Not removing " )
return
m = ldb . Message ( )
m . dn = dn
m [ ' old_value ' ] = ldb . MessageElement ( val , ldb . FLAG_MOD_DELETE , attrname )
2011-10-07 11:57:34 +04:00
if self . do_modify ( m , [ " show_recycled:1 " , " local_oid: %s :0 " % dsdb . DSDB_CONTROL_DBCHECK ] ,
2011-10-06 07:21:41 +04:00
" Failed to remove deleted DN attribute %s " % attrname ) :
self . report ( " Removed deleted DN on attribute %s " % attrname )
def err_missing_dn_GUID ( self , dn , attrname , val , dsdb_dn ) :
2012-02-19 02:59:48 +04:00
""" handle a missing target DN (both GUID and DN string form are missing) """
2011-10-06 07:21:41 +04:00
# check if its a backlink
linkID = self . samdb_schema . get_linkId_from_lDAPDisplayName ( attrname )
if ( linkID & 1 == 0 ) and str ( dsdb_dn ) . find ( ' DEL \\ 0A ' ) == - 1 :
self . report ( " Not removing dangling forward link " )
return
self . err_deleted_dn ( dn , attrname , val , dsdb_dn , dsdb_dn )
2011-06-22 14:01:58 +04:00
def err_incorrect_dn_GUID ( self , dn , attrname , val , dsdb_dn , errstr ) :
2012-02-19 02:59:48 +04:00
""" handle a missing GUID extended DN component """
2011-06-22 14:01:58 +04:00
self . report ( " ERROR: %s component for %s in object %s - %s " % ( errstr , attrname , dn , val ) )
2011-09-22 03:58:09 +04:00
controls = [ " extended_dn:1:1 " , " show_recycled:1 " ]
2011-06-22 14:01:58 +04:00
try :
2011-06-22 14:53:44 +04:00
res = self . samdb . search ( base = str ( dsdb_dn . dn ) , scope = ldb . SCOPE_BASE ,
2011-06-22 16:06:18 +04:00
attrs = [ ] , controls = controls )
2011-06-22 14:01:58 +04:00
except ldb . LdbError , ( enum , estr ) :
2011-10-06 07:21:41 +04:00
self . report ( " unable to find object for DN %s - ( %s ) " % ( dsdb_dn . dn , estr ) )
self . err_missing_dn_GUID ( dn , attrname , val , dsdb_dn )
2011-06-22 14:01:58 +04:00
return
2011-09-22 03:58:09 +04:00
if len ( res ) == 0 :
2011-10-06 07:21:41 +04:00
self . report ( " unable to find object for DN %s " % dsdb_dn . dn )
self . err_missing_dn_GUID ( dn , attrname , val , dsdb_dn )
2011-09-22 03:58:09 +04:00
return
2011-06-22 14:01:58 +04:00
dsdb_dn . dn = res [ 0 ] . dn
2011-07-11 05:09:00 +04:00
if not self . confirm_all ( ' Change DN to %s ? ' % str ( dsdb_dn ) , ' fix_all_DN_GUIDs ' ) :
2011-06-22 14:01:58 +04:00
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 )
2011-07-11 10:55:36 +04:00
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to fix %s on attribute %s " % ( errstr , attrname ) ) :
self . report ( " Fixed %s on attribute %s " % ( errstr , attrname ) )
2011-06-22 14:01:58 +04:00
2013-02-11 01:25:41 +04:00
def err_incorrect_binary_dn ( self , dn , attrname , val , dsdb_dn , errstr ) :
""" handle an incorrect binary DN component """
self . report ( " ERROR: %s binary component for %s in object %s - %s " % ( errstr , attrname , dn , val ) )
controls = [ " extended_dn:1:1 " , " show_recycled:1 " ]
if not self . confirm_all ( ' Change DN to %s ? ' % str ( dsdb_dn ) , ' fix_all_binary_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 . do_modify ( m , [ " show_recycled:1 " ] ,
" Failed to fix %s on attribute %s " % ( errstr , attrname ) ) :
self . report ( " Fixed %s on attribute %s " % ( errstr , attrname ) )
2011-06-22 21:28:25 +04:00
def err_dn_target_mismatch ( self , dn , attrname , val , dsdb_dn , correct_dn , errstr ) :
2012-02-19 02:59:48 +04:00
""" handle a DN string being incorrect """
2011-06-22 14:01:58 +04:00
self . report ( " ERROR: incorrect DN string component for %s in object %s - %s " % ( attrname , dn , val ) )
dsdb_dn . dn = correct_dn
2011-07-11 05:09:00 +04:00
if not self . confirm_all ( ' Change DN to %s ? ' % str ( dsdb_dn ) , ' fix_all_target_mismatch ' ) :
2011-06-22 14:01:58 +04:00
self . report ( " Not fixing %s " % errstr )
return
m = ldb . Message ( )
m . dn = dn
2011-09-23 11:37:23 +04:00
m [ ' old_value ' ] = ldb . MessageElement ( val , ldb . FLAG_MOD_DELETE , attrname )
2011-06-22 14:01:58 +04:00
m [ ' new_value ' ] = ldb . MessageElement ( str ( dsdb_dn ) , ldb . FLAG_MOD_ADD , attrname )
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to fix incorrect DN string on attribute %s " % attrname ) :
self . report ( " Fixed incorrect DN string on attribute %s " % ( attrname ) )
2011-06-22 14:01:58 +04:00
2011-07-05 06:42:53 +04:00
def err_unknown_attribute ( self , obj , attrname ) :
''' handle an unknown attribute error '''
self . report ( " ERROR: unknown attribute ' %s ' in %s " % ( attrname , obj . dn ) )
if not self . confirm_all ( ' Remove unknown attribute %s ' % attrname , ' remove_all_unknown_attributes ' ) :
self . report ( " Not removing %s " % attrname )
return
m = ldb . Message ( )
m . dn = obj . dn
m [ ' old_value ' ] = ldb . MessageElement ( [ ] , ldb . FLAG_MOD_DELETE , attrname )
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " relax:0 " , " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to remove unknown attribute %s " % attrname ) :
self . report ( " Removed unknown attribute %s " % ( attrname ) )
def err_missing_backlink ( self , obj , attrname , val , backlink_name , target_dn ) :
''' handle a missing backlink value '''
self . report ( " ERROR: missing backlink attribute ' %s ' in %s for link %s in %s " % ( backlink_name , target_dn , attrname , obj . dn ) )
if not self . confirm_all ( ' Fix missing backlink %s ' % backlink_name , ' fix_all_missing_backlinks ' ) :
self . report ( " Not fixing missing backlink %s " % backlink_name )
2011-07-05 06:42:53 +04:00
return
2011-07-11 10:55:36 +04:00
m = ldb . Message ( )
m . dn = obj . dn
m [ ' old_value ' ] = ldb . MessageElement ( val , ldb . FLAG_MOD_DELETE , attrname )
m [ ' new_value ' ] = ldb . MessageElement ( val , ldb . FLAG_MOD_ADD , attrname )
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to fix missing backlink %s " % backlink_name ) :
self . report ( " Fixed missing backlink %s " % ( backlink_name ) )
2012-04-18 09:46:14 +04:00
def err_incorrect_rmd_flags ( self , obj , attrname , revealed_dn ) :
''' handle a incorrect RMD_FLAGS value '''
rmd_flags = int ( revealed_dn . dn . get_extended_component ( " RMD_FLAGS " ) )
self . report ( " ERROR: incorrect RMD_FLAGS value %u for attribute ' %s ' in %s for link %s " % ( rmd_flags , attrname , obj . dn , revealed_dn . dn . extended_str ( ) ) )
if not self . confirm_all ( ' Fix incorrect RMD_FLAGS %u ' % rmd_flags , ' fix_rmd_flags ' ) :
self . report ( " Not fixing incorrect RMD_FLAGS %u " % rmd_flags )
return
m = ldb . Message ( )
m . dn = obj . dn
m [ ' old_value ' ] = ldb . MessageElement ( str ( revealed_dn ) , ldb . FLAG_MOD_DELETE , attrname )
if self . do_modify ( m , [ " show_recycled:1 " , " reveal_internals:0 " , " show_deleted:0 " ] ,
" Failed to fix incorrect RMD_FLAGS %u " % rmd_flags ) :
self . report ( " Fixed incorrect RMD_FLAGS %u " % ( rmd_flags ) )
2011-07-12 05:26:29 +04:00
def err_orphaned_backlink ( self , obj , attrname , val , link_name , target_dn ) :
2011-07-11 10:55:36 +04:00
''' handle a orphaned backlink value '''
2011-07-12 05:26:29 +04:00
self . report ( " ERROR: orphaned backlink attribute ' %s ' in %s for link %s in %s " % ( attrname , obj . dn , link_name , target_dn ) )
if not self . confirm_all ( ' Remove orphaned backlink %s ' % link_name , ' fix_all_orphaned_backlinks ' ) :
self . report ( " Not removing orphaned backlink %s " % link_name )
2011-07-11 10:55:36 +04:00
return
m = ldb . Message ( )
2011-07-12 05:26:29 +04:00
m . dn = obj . dn
m [ ' value ' ] = ldb . MessageElement ( val , ldb . FLAG_MOD_DELETE , attrname )
2011-09-22 03:58:09 +04:00
if self . do_modify ( m , [ " show_recycled:1 " , " relax:0 " ] ,
2011-07-12 05:26:29 +04:00
" Failed to fix orphaned backlink %s " % link_name ) :
self . report ( " Fixed orphaned backlink %s " % ( link_name ) )
2011-07-05 06:42:53 +04:00
2012-04-19 08:14:35 +04:00
def err_no_fsmoRoleOwner ( self , obj ) :
''' handle a missing fSMORoleOwner '''
self . report ( " ERROR: fSMORoleOwner not found for role %s " % ( obj . dn ) )
res = self . samdb . search ( " " ,
scope = ldb . SCOPE_BASE , attrs = [ " dsServiceName " ] )
assert len ( res ) == 1
serviceName = res [ 0 ] [ " dsServiceName " ] [ 0 ]
if not self . confirm_all ( ' Sieze role %s onto current DC by adding fSMORoleOwner= %s ' % ( obj . dn , serviceName ) , ' seize_fsmo_role ' ) :
self . report ( " Not Siezing role %s onto current DC by adding fSMORoleOwner= %s " % ( obj . dn , serviceName ) )
return
m = ldb . Message ( )
m . dn = obj . dn
m [ ' value ' ] = ldb . MessageElement ( serviceName , ldb . FLAG_MOD_ADD , ' fSMORoleOwner ' )
if self . do_modify ( m , [ ] ,
" Failed to sieze role %s onto current DC by adding fSMORoleOwner= %s " % ( obj . dn , serviceName ) ) :
self . report ( " Siezed role %s onto current DC by adding fSMORoleOwner= %s " % ( obj . dn , serviceName ) )
2012-07-06 13:59:09 +04:00
def err_missing_parent ( self , obj ) :
''' handle a missing parent '''
self . report ( " ERROR: parent object not found for %s " % ( obj . dn ) )
if not self . confirm_all ( ' Move object %s into LostAndFound? ' % ( obj . dn ) , ' move_to_lost_and_found ' ) :
self . report ( ' Not moving object %s into LostAndFound ' % ( obj . dn ) )
return
2012-07-28 04:59:09 +04:00
keep_transaction = True
self . samdb . transaction_start ( )
try :
nc_root = self . samdb . get_nc_root ( obj . dn ) ;
lost_and_found = self . samdb . get_wellknown_dn ( nc_root , dsdb . DS_GUID_LOSTANDFOUND_CONTAINER )
new_dn = ldb . Dn ( self . samdb , str ( obj . dn ) )
new_dn . remove_base_components ( len ( new_dn ) - 1 )
if self . do_rename ( obj . dn , new_dn , lost_and_found , [ " show_deleted:0 " , " relax:0 " ] ,
" Failed to rename object %s into lostAndFound at %s " % ( obj . dn , new_dn + lost_and_found ) ) :
self . report ( " Renamed object %s into lostAndFound at %s " % ( obj . dn , new_dn + lost_and_found ) )
m = ldb . Message ( )
m . dn = obj . dn
m [ ' lastKnownParent ' ] = ldb . MessageElement ( str ( obj . dn . parent ( ) ) , ldb . FLAG_MOD_REPLACE , ' lastKnownParent ' )
2012-09-27 20:30:47 +04:00
if self . do_modify ( m , [ ] ,
2012-07-28 04:59:09 +04:00
" Failed to set lastKnownParent on lostAndFound object at %s " % ( new_dn + lost_and_found ) ) :
self . report ( " Set lastKnownParent on lostAndFound object at %s " % ( new_dn + lost_and_found ) )
keep_transaction = True
except :
self . samdb . transaction_cancel ( )
raise
if keep_transaction :
self . samdb . transaction_commit ( )
else :
self . samdb . transaction_cancel ( )
2012-07-06 13:59:09 +04:00
2012-07-17 05:10:41 +04:00
def err_wrong_instancetype ( self , obj , calculated_instancetype ) :
''' handle a wrong instanceType '''
self . report ( " ERROR: wrong instanceType %s on %s , should be %d " % ( obj [ " instanceType " ] , obj . dn , calculated_instancetype ) )
if not self . confirm_all ( ' Change instanceType from %s to %d on %s ? ' % ( obj [ " instanceType " ] , calculated_instancetype , obj . dn ) , ' fix_instancetype ' ) :
self . report ( ' Not changing instanceType from %s to %d on %s ' % ( obj [ " instanceType " ] , calculated_instancetype , obj . dn ) )
return
m = ldb . Message ( )
m . dn = obj . dn
m [ ' value ' ] = ldb . MessageElement ( str ( calculated_instancetype ) , ldb . FLAG_MOD_REPLACE , ' instanceType ' )
if self . do_modify ( m , [ " local_oid: %s :0 " % dsdb . DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA ] ,
" Failed to correct missing instanceType on %s by setting instanceType= %d " % ( obj . dn , calculated_instancetype ) ) :
self . report ( " Corrected instancetype on %s by setting instanceType= %d " % ( obj . dn , calculated_instancetype ) )
2012-04-18 09:46:14 +04:00
def find_revealed_link ( self , dn , attrname , guid ) :
''' return a revealed link in an object '''
res = self . samdb . search ( base = dn , scope = ldb . SCOPE_BASE , attrs = [ attrname ] ,
controls = [ " show_deleted:0 " , " extended_dn:0 " , " reveal_internals:0 " ] )
syntax_oid = self . samdb_schema . get_syntax_oid_from_lDAPDisplayName ( attrname )
for val in res [ 0 ] [ attrname ] :
dsdb_dn = dsdb_Dn ( self . samdb , val , syntax_oid )
guid2 = dsdb_dn . dn . get_extended_component ( " GUID " )
if guid == guid2 :
return dsdb_dn
return None
2011-06-22 14:01:58 +04:00
def check_dn ( self , obj , attrname , syntax_oid ) :
''' check a DN attribute for correctness '''
error_count = 0
for val in obj [ attrname ] :
2011-10-20 06:24:45 +04:00
dsdb_dn = dsdb_Dn ( self . samdb , val , syntax_oid )
2011-06-22 14:01:58 +04:00
# all DNs should have a GUID component
guid = dsdb_dn . dn . get_extended_component ( " GUID " )
if guid is None :
error_count + = 1
2012-02-19 02:59:48 +04:00
self . err_incorrect_dn_GUID ( obj . dn , attrname , val , dsdb_dn ,
" missing GUID " )
2011-06-22 14:01:58 +04:00
continue
guidstr = str ( misc . GUID ( guid ) )
2012-02-19 02:59:48 +04:00
attrs = [ ' isDeleted ' ]
2013-02-11 01:25:41 +04:00
if ( str ( attrname ) . lower ( ) == ' msds-hasinstantiatedncs ' ) and ( obj . dn == self . ntds_dsa ) :
fixing_msDS_HasInstantiatedNCs = True
attrs . append ( " instanceType " )
else :
fixing_msDS_HasInstantiatedNCs = False
2011-10-06 07:21:41 +04:00
linkID = self . samdb_schema . get_linkId_from_lDAPDisplayName ( attrname )
2011-07-13 07:26:19 +04:00
reverse_link_name = self . samdb_schema . get_backlink_from_lDAPDisplayName ( attrname )
2011-07-12 05:26:29 +04:00
if reverse_link_name is not None :
attrs . append ( reverse_link_name )
2011-07-11 10:55:36 +04:00
2011-06-22 14:01:58 +04:00
# check its the right GUID
try :
res = self . samdb . search ( base = " <GUID= %s > " % guidstr , scope = ldb . SCOPE_BASE ,
2011-09-22 03:58:09 +04:00
attrs = attrs , controls = [ " extended_dn:1:1 " , " show_recycled:1 " ] )
2011-06-22 14:01:58 +04:00
except ldb . LdbError , ( enum , estr ) :
error_count + = 1
self . err_incorrect_dn_GUID ( obj . dn , attrname , val , dsdb_dn , " incorrect GUID " )
continue
2013-02-11 01:25:41 +04:00
if fixing_msDS_HasInstantiatedNCs :
dsdb_dn . prefix = " B:8: %08X : " % int ( res [ 0 ] [ ' instanceType ' ] [ 0 ] )
dsdb_dn . binary = " %08X " % int ( res [ 0 ] [ ' instanceType ' ] [ 0 ] )
if str ( dsdb_dn ) != val :
error_count + = 1
self . err_incorrect_binary_dn ( obj . dn , attrname , val , dsdb_dn , " incorrect instanceType part of Binary DN " )
continue
2011-07-11 06:23:01 +04:00
# now we have two cases - the source object might or might not be deleted
is_deleted = ' isDeleted ' in obj and obj [ ' isDeleted ' ] [ 0 ] . upper ( ) == ' TRUE '
target_is_deleted = ' isDeleted ' in res [ 0 ] and res [ 0 ] [ ' isDeleted ' ] [ 0 ] . upper ( ) == ' TRUE '
# the target DN is not allowed to be deleted, unless the target DN is the
# special Deleted Objects container
if target_is_deleted and not is_deleted and not self . is_deleted_objects_dn ( dsdb_dn ) :
2011-06-22 14:01:58 +04:00
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
2011-06-22 21:28:25 +04:00
self . err_dn_target_mismatch ( obj . dn , attrname , val , dsdb_dn ,
res [ 0 ] . dn , " incorrect string version of DN " )
2011-06-22 14:01:58 +04:00
continue
2012-04-18 09:46:14 +04:00
if is_deleted and not target_is_deleted and reverse_link_name is not None :
revealed_dn = self . find_revealed_link ( obj . dn , attrname , guid )
rmd_flags = revealed_dn . dn . get_extended_component ( " RMD_FLAGS " )
2012-09-27 20:30:47 +04:00
if rmd_flags is not None and ( int ( rmd_flags ) & 1 ) == 0 :
2012-04-18 09:46:14 +04:00
# the RMD_FLAGS for this link should be 1, as the target is deleted
self . err_incorrect_rmd_flags ( obj , attrname , revealed_dn )
continue
2011-07-12 05:26:29 +04:00
# check the reverse_link is correct if there should be one
if reverse_link_name is not None :
2011-07-11 10:55:36 +04:00
match_count = 0
2011-07-12 05:26:29 +04:00
if reverse_link_name in res [ 0 ] :
for v in res [ 0 ] [ reverse_link_name ] :
2011-07-11 10:55:36 +04:00
if v == obj . dn . extended_str ( ) :
match_count + = 1
if match_count != 1 :
error_count + = 1
2011-10-06 07:21:41 +04:00
if linkID & 1 :
2011-07-12 05:26:29 +04:00
self . err_orphaned_backlink ( obj , attrname , val , reverse_link_name , dsdb_dn . dn )
2011-07-11 10:55:36 +04:00
else :
2011-07-12 05:26:29 +04:00
self . err_missing_backlink ( obj , attrname , val , reverse_link_name , dsdb_dn . dn )
2011-07-11 10:55:36 +04:00
continue
2011-06-22 14:01:58 +04:00
return error_count
2011-11-13 17:09:24 +04:00
def get_originating_time ( self , val , attid ) :
''' Read metadata properties and return the originating time for
a given attributeId .
: return : the originating time or 0 if not found
'''
repl = ndr_unpack ( drsblobs . replPropertyMetaDataBlob , str ( val ) )
obj = repl . ctr
for o in repl . ctr . array :
if o . attid == attid :
return o . originating_change_time
return 0
2011-07-07 00:31:21 +04:00
def process_metadata ( self , val ) :
''' Read metadata properties and list attributes in it '''
list_att = [ ]
2011-07-11 08:28:19 +04:00
repl = ndr_unpack ( drsblobs . replPropertyMetaDataBlob , str ( val ) )
2011-07-07 00:31:21 +04:00
obj = repl . ctr
for o in repl . ctr . array :
2011-07-11 08:28:19 +04:00
att = self . samdb_schema . get_lDAPDisplayName_by_attid ( o . attid )
2011-07-07 00:31:21 +04:00
list_att . append ( att . lower ( ) )
return list_att
2011-07-11 08:05:30 +04:00
def fix_metadata ( self , dn , attr ) :
''' re-write replPropertyMetaData elements for a single attribute for a
object . This is used to fix missing replPropertyMetaData elements '''
res = self . samdb . search ( base = dn , scope = ldb . SCOPE_BASE , attrs = [ attr ] ,
2011-09-22 03:58:09 +04:00
controls = [ " search_options:1:2 " , " show_recycled:1 " ] )
2011-07-07 00:31:21 +04:00
msg = res [ 0 ]
nmsg = ldb . Message ( )
nmsg . dn = dn
2011-07-11 08:05:30 +04:00
nmsg [ attr ] = ldb . MessageElement ( msg [ attr ] , ldb . FLAG_MOD_REPLACE , attr )
2011-09-22 03:58:09 +04:00
if self . do_modify ( nmsg , [ " relax:0 " , " provision:0 " , " show_recycled:1 " ] ,
2011-07-11 10:55:36 +04:00
" Failed to fix metadata for attribute %s " % attr ) :
self . report ( " Fixed metadata for attribute %s " % attr )
2011-07-07 00:31:21 +04:00
2013-01-19 12:41:00 +04:00
def ace_get_effective_inherited_type ( self , ace ) :
if ace . flags & security . SEC_ACE_FLAG_INHERIT_ONLY :
return None
check = False
if ace . type == security . SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT :
check = True
elif ace . type == security . SEC_ACE_TYPE_ACCESS_DENIED_OBJECT :
check = True
elif ace . type == security . SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT :
check = True
elif ace . type == security . SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT :
check = True
if not check :
return None
if not ace . object . flags & security . SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT :
return None
return str ( ace . object . inherited_type )
def lookup_class_schemaIDGUID ( self , cls ) :
if cls in self . class_schemaIDGUID :
return self . class_schemaIDGUID [ cls ]
flt = " (&(ldapDisplayName= %s )(objectClass=classSchema)) " % cls
res = self . samdb . search ( base = self . schema_dn ,
expression = flt ,
attrs = [ " schemaIDGUID " ] )
t = str ( ndr_unpack ( misc . GUID , res [ 0 ] [ " schemaIDGUID " ] [ 0 ] ) )
self . class_schemaIDGUID [ cls ] = t
return t
def process_sd ( self , dn , obj ) :
sd_attr = " nTSecurityDescriptor "
sd_val = obj [ sd_attr ]
sd = ndr_unpack ( security . descriptor , str ( sd_val ) )
is_deleted = ' isDeleted ' in obj and obj [ ' isDeleted ' ] [ 0 ] . upper ( ) == ' TRUE '
if is_deleted :
# we don't fix deleted objects
return ( sd , None )
sd_clean = security . descriptor ( )
sd_clean . owner_sid = sd . owner_sid
sd_clean . group_sid = sd . group_sid
sd_clean . type = sd . type
sd_clean . revision = sd . revision
broken = False
last_inherited_type = None
aces = [ ]
if sd . sacl is not None :
aces = sd . sacl . aces
for i in range ( 0 , len ( aces ) ) :
ace = aces [ i ]
if not ace . flags & security . SEC_ACE_FLAG_INHERITED_ACE :
sd_clean . sacl_add ( ace )
continue
t = self . ace_get_effective_inherited_type ( ace )
if t is None :
continue
if last_inherited_type is not None :
if t != last_inherited_type :
# if it inherited from more than
# one type it's very likely to be broken
#
# If not the recalculation will calculate
# the same result.
broken = True
continue
last_inherited_type = t
aces = [ ]
if sd . dacl is not None :
aces = sd . dacl . aces
for i in range ( 0 , len ( aces ) ) :
ace = aces [ i ]
if not ace . flags & security . SEC_ACE_FLAG_INHERITED_ACE :
sd_clean . dacl_add ( ace )
continue
t = self . ace_get_effective_inherited_type ( ace )
if t is None :
continue
if last_inherited_type is not None :
if t != last_inherited_type :
# if it inherited from more than
# one type it's very likely to be broken
#
# If not the recalculation will calculate
# the same result.
broken = True
continue
last_inherited_type = t
if broken :
return ( sd_clean , sd )
if last_inherited_type is None :
# ok
return ( sd , None )
cls = None
try :
cls = obj [ " objectClass " ] [ - 1 ]
except KeyError , e :
pass
if cls is None :
res = self . samdb . search ( base = dn , scope = ldb . SCOPE_BASE ,
attrs = [ " isDeleted " , " objectClass " ] ,
controls = [ " show_recycled:1 " ] )
o = res [ 0 ]
is_deleted = ' isDeleted ' in o and o [ ' isDeleted ' ] [ 0 ] . upper ( ) == ' TRUE '
if is_deleted :
# we don't fix deleted objects
return ( sd , None )
cls = o [ " objectClass " ] [ - 1 ]
t = self . lookup_class_schemaIDGUID ( cls )
if t != last_inherited_type :
# broken
return ( sd_clean , sd )
# ok
return ( sd , None )
def err_wrong_sd ( self , dn , sd , sd_broken ) :
2013-02-11 07:50:49 +04:00
''' re-write the SD due to incorrect inherited ACEs '''
2013-01-19 12:41:00 +04:00
sd_attr = " nTSecurityDescriptor "
sd_val = ndr_pack ( sd )
sd_flags = security . SECINFO_DACL | security . SECINFO_SACL
if not self . confirm_all ( ' Fix %s on %s ? ' % ( sd_attr , dn ) , ' fix_ntsecuritydescriptor ' ) :
self . report ( ' Not fixing %s on %s \n ' % ( sd_attr , dn ) )
return
nmsg = ldb . Message ( )
nmsg . dn = dn
nmsg [ sd_attr ] = ldb . MessageElement ( sd_val , ldb . FLAG_MOD_REPLACE , sd_attr )
if self . do_modify ( nmsg , [ " sd_flags:1: %d " % sd_flags ] ,
" Failed to fix metadata for attribute %s " % sd_attr ) :
self . report ( " Fixed attribute ' %s ' of ' %s ' \n " % ( sd_attr , dn ) )
2012-04-19 08:14:35 +04:00
def is_fsmo_role ( self , dn ) :
if dn == self . samdb . domain_dn :
return True
if dn == self . infrastructure_dn :
return True
if dn == self . naming_dn :
return True
if dn == self . schema_dn :
return True
if dn == self . rid_dn :
return True
2012-09-27 20:30:47 +04:00
2012-04-19 08:14:35 +04:00
return False
2012-07-17 05:10:41 +04:00
def calculate_instancetype ( self , dn ) :
instancetype = 0
nc_root = self . samdb . get_nc_root ( dn )
if dn == nc_root :
instancetype | = dsdb . INSTANCE_TYPE_IS_NC_HEAD
try :
self . samdb . search ( base = dn . parent ( ) , scope = ldb . SCOPE_BASE , attrs = [ ] , controls = [ " show_recycled:1 " ] )
except ldb . LdbError , ( enum , estr ) :
if enum != ldb . ERR_NO_SUCH_OBJECT :
raise
else :
instancetype | = dsdb . INSTANCE_TYPE_NC_ABOVE
if self . write_ncs is not None and str ( nc_root ) in self . write_ncs :
instancetype | = dsdb . INSTANCE_TYPE_WRITE
return instancetype
2011-06-22 14:44:35 +04:00
def check_object ( self , dn , attrs = [ ' * ' ] ) :
2011-06-22 14:01:58 +04:00
''' check one object '''
if self . verbose :
self . report ( " Checking object %s " % dn )
2011-07-07 00:31:21 +04:00
if ' * ' in attrs :
attrs . append ( " replPropertyMetaData " )
2011-12-08 04:47:59 +04:00
try :
2013-01-19 12:41:00 +04:00
sd_flags = 0
sd_flags | = security . SECINFO_OWNER
sd_flags | = security . SECINFO_GROUP
sd_flags | = security . SECINFO_DACL
sd_flags | = security . SECINFO_SACL
2011-12-08 04:47:59 +04:00
res = self . samdb . search ( base = dn , scope = ldb . SCOPE_BASE ,
2013-01-19 12:41:00 +04:00
controls = [
" extended_dn:1:1 " ,
" show_recycled:1 " ,
" show_deleted:1 " ,
" sd_flags:1: %d " % sd_flags ,
] ,
2011-12-08 04:47:59 +04:00
attrs = attrs )
except ldb . LdbError , ( enum , estr ) :
if enum == ldb . ERR_NO_SUCH_OBJECT :
if self . in_transaction :
self . report ( " ERROR: Object %s disappeared during check " % dn )
return 1
return 0
raise
2011-06-22 14:01:58 +04:00
if len ( res ) != 1 :
2011-12-08 04:47:59 +04:00
self . report ( " ERROR: Object %s failed to load during check " % dn )
2011-06-22 14:01:58 +04:00
return 1
obj = res [ 0 ]
error_count = 0
2011-07-07 00:31:21 +04:00
list_attrs_from_md = [ ]
list_attrs_seen = [ ]
2011-07-13 04:12:48 +04:00
got_repl_property_meta_data = False
2011-07-07 00:31:21 +04:00
2011-06-22 14:01:58 +04:00
for attrname in obj :
if attrname == ' dn ' :
continue
2011-07-07 00:31:21 +04:00
if str ( attrname ) . lower ( ) == ' replpropertymetadata ' :
list_attrs_from_md = self . process_metadata ( obj [ attrname ] )
2011-07-13 04:12:48 +04:00
got_repl_property_meta_data = True
2011-07-07 00:31:21 +04:00
continue
2013-01-19 12:41:00 +04:00
if str ( attrname ) . lower ( ) == ' ntsecuritydescriptor ' :
( sd , sd_broken ) = self . process_sd ( dn , obj )
if sd_broken is not None :
self . err_wrong_sd ( dn , sd , sd_broken )
error_count + = 1
continue
2012-04-11 19:18:37 +04:00
if str ( attrname ) . lower ( ) == ' objectclass ' :
normalised = self . samdb . dsdb_normalise_attributes ( self . samdb_schema , attrname , list ( obj [ attrname ] ) )
if list ( normalised ) != list ( obj [ attrname ] ) :
self . err_normalise_mismatch_replace ( dn , attrname , list ( obj [ attrname ] ) )
error_count + = 1
continue
2011-06-22 14:01:58 +04:00
# 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
2011-07-05 06:42:53 +04:00
try :
syntax_oid = self . samdb_schema . get_syntax_oid_from_lDAPDisplayName ( attrname )
except Exception , msg :
self . err_unknown_attribute ( obj , attrname )
error_count + = 1
continue
2011-06-22 14:01:58 +04:00
2011-07-07 00:31:21 +04:00
flag = self . samdb_schema . get_systemFlags_from_lDAPDisplayName ( attrname )
if ( not flag & dsdb . DS_FLAG_ATTR_NOT_REPLICATED
and not flag & dsdb . DS_FLAG_ATTR_IS_CONSTRUCTED
and not self . samdb_schema . get_linkId_from_lDAPDisplayName ( attrname ) ) :
list_attrs_seen . append ( str ( attrname ) . lower ( ) )
2011-06-22 14:01:58 +04:00
if syntax_oid in [ dsdb . DSDB_SYNTAX_BINARY_DN , dsdb . DSDB_SYNTAX_OR_NAME ,
2011-08-31 09:55:27 +04:00
dsdb . DSDB_SYNTAX_STRING_DN , ldb . SYNTAX_DN ] :
2011-06-22 14:01:58 +04:00
# it's some form of DN, do specialised checking on those
error_count + = self . check_dn ( obj , attrname , syntax_oid )
# check for incorrectly normalised attributes
for val in obj [ attrname ] :
normalised = self . samdb . dsdb_normalise_attributes ( self . samdb_schema , attrname , [ val ] )
if len ( normalised ) != 1 or normalised [ 0 ] != val :
self . err_normalise_mismatch ( dn , attrname , obj [ attrname ] )
error_count + = 1
break
2011-07-07 00:31:21 +04:00
2012-07-17 05:10:41 +04:00
if str ( attrname ) . lower ( ) == " instancetype " :
calculated_instancetype = self . calculate_instancetype ( dn )
if len ( obj [ " instanceType " ] ) != 1 or obj [ " instanceType " ] [ 0 ] != str ( calculated_instancetype ) :
self . err_wrong_instancetype ( obj , calculated_instancetype )
2011-07-07 00:31:21 +04:00
show_dn = True
2011-07-13 04:12:48 +04:00
if got_repl_property_meta_data :
2011-11-13 17:09:24 +04:00
rdn = ( str ( dn ) . split ( " , " ) ) [ 0 ]
if rdn == " CN=Deleted Objects " :
isDeletedAttId = 131120
# It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
expectedTimeDo = 2650466015990000000
originating = self . get_originating_time ( obj [ " replPropertyMetaData " ] , isDeletedAttId )
if originating != expectedTimeDo :
if self . confirm_all ( " Fix isDeleted originating_change_time on ' %s ' " % str ( dn ) , ' fix_time_metadata ' ) :
nmsg = ldb . Message ( )
nmsg . dn = dn
nmsg [ " isDeleted " ] = ldb . MessageElement ( " TRUE " , ldb . FLAG_MOD_REPLACE , " isDeleted " )
error_count + = 1
self . samdb . modify ( nmsg , controls = [ " provision:0 " ] )
else :
self . report ( " Not fixing isDeleted originating_change_time on ' %s ' " % str ( dn ) )
2011-07-13 04:12:48 +04:00
for att in list_attrs_seen :
if not att in list_attrs_from_md :
if show_dn :
self . report ( " On object %s " % dn )
show_dn = False
error_count + = 1
self . report ( " ERROR: Attribute %s not present in replication metadata " % att )
if not self . confirm_all ( " Fix missing replPropertyMetaData element ' %s ' " % att , ' fix_all_metadata ' ) :
self . report ( " Not fixing missing replPropertyMetaData element ' %s ' " % att )
continue
self . fix_metadata ( dn , att )
2011-07-07 00:31:21 +04:00
2012-04-19 08:14:35 +04:00
if self . is_fsmo_role ( dn ) :
if " fSMORoleOwner " not in obj :
self . err_no_fsmoRoleOwner ( obj )
error_count + = 1
2012-07-06 13:59:09 +04:00
try :
if dn != self . samdb . get_root_basedn ( ) :
res = self . samdb . search ( base = dn . parent ( ) , scope = ldb . SCOPE_BASE ,
controls = [ " show_recycled:1 " , " show_deleted:1 " ] )
except ldb . LdbError , ( enum , estr ) :
if enum == ldb . ERR_NO_SUCH_OBJECT :
self . err_missing_parent ( obj )
error_count + = 1
else :
raise
2011-06-22 14:01:58 +04:00
return error_count
2011-07-12 05:05:43 +04:00
2011-08-11 10:59:11 +04:00
################################################################
# check special @ROOTDSE attributes
def check_rootdse ( self ) :
''' check the @ROOTDSE special object '''
dn = ldb . Dn ( self . samdb , ' @ROOTDSE ' )
if self . verbose :
self . report ( " Checking object %s " % dn )
res = self . samdb . search ( base = dn , scope = ldb . SCOPE_BASE )
if len ( res ) != 1 :
self . report ( " Object %s disappeared during check " % dn )
return 1
obj = res [ 0 ]
error_count = 0
# check that the dsServiceName is in GUID form
if not ' dsServiceName ' in obj :
self . report ( ' ERROR: dsServiceName missing in @ROOTDSE ' )
return error_count + 1
if not obj [ ' dsServiceName ' ] [ 0 ] . startswith ( ' <GUID= ' ) :
self . report ( ' ERROR: dsServiceName not in GUID form in @ROOTDSE ' )
error_count + = 1
if not self . confirm ( ' Change dsServiceName to GUID form? ' ) :
return error_count
res = self . samdb . search ( base = ldb . Dn ( self . samdb , obj [ ' dsServiceName ' ] [ 0 ] ) ,
scope = ldb . SCOPE_BASE , attrs = [ ' objectGUID ' ] )
guid_str = str ( ndr_unpack ( misc . GUID , res [ 0 ] [ ' objectGUID ' ] [ 0 ] ) )
m = ldb . Message ( )
m . dn = dn
m [ ' dsServiceName ' ] = ldb . MessageElement ( " <GUID= %s > " % guid_str ,
ldb . FLAG_MOD_REPLACE , ' dsServiceName ' )
if self . do_modify ( m , [ ] , " Failed to change dsServiceName to GUID form " , validate = False ) :
self . report ( " Changed dsServiceName to GUID form " )
return error_count
2011-07-12 05:05:43 +04:00
###############################################
# re-index the database
def reindex_database ( self ) :
''' re-index the whole database '''
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , " @ATTRIBUTES " )
m [ ' add ' ] = ldb . MessageElement ( ' NONE ' , ldb . FLAG_MOD_ADD , ' force_reindex ' )
m [ ' delete ' ] = ldb . MessageElement ( ' NONE ' , ldb . FLAG_MOD_DELETE , ' force_reindex ' )
return self . do_modify ( m , [ ] , ' re-indexed database ' , validate = False )
2012-08-23 09:18:13 +04:00
###############################################
# reset @MODULES
def reset_modules ( self ) :
''' reset @MODULES to that needed for current sam.ldb (to read a very old database) '''
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , " @MODULES " )
m [ ' @LIST ' ] = ldb . MessageElement ( ' samba_dsdb ' , ldb . FLAG_MOD_REPLACE , ' @LIST ' )
return self . do_modify ( m , [ ] , ' reset @MODULES on database ' , validate = False )