2018-12-12 03:39:24 +03:00
#!/usr/bin/env python3
2010-11-04 00:43:21 +03:00
# -*- coding: utf-8 -*-
#
# script to verify cached prefixMap on remote
# server against the prefixMap stored in Schema NC
#
# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import os
import sys
from optparse import OptionParser
sys . path . insert ( 0 , " bin/python " )
import samba
import samba . getopt as options
from ldb import SCOPE_BASE , SCOPE_SUBTREE
from samba . dcerpc import drsuapi , misc , drsblobs
from samba . drs_utils import drs_DsBind
from samba . samdb import SamDB
from samba . auth import system_session
from samba . ndr import ndr_pack , ndr_unpack
2020-07-04 05:27:06 +03:00
2010-11-04 00:43:21 +03:00
def _samdb_fetch_pfm ( samdb ) :
""" Fetch prefixMap stored in SamDB using LDB connection """
res = samdb . search ( base = samdb . get_schema_basedn ( ) , expression = " " , scope = SCOPE_BASE , attrs = [ " * " ] )
assert len ( res ) == 1
pfm = ndr_unpack ( drsblobs . prefixMapBlob ,
str ( res [ 0 ] [ ' prefixMap ' ] ) )
2010-12-22 02:09:59 +03:00
pfm_schi = _samdb_fetch_schi ( samdb )
return ( pfm . ctr , pfm_schi )
2018-07-30 09:20:39 +03:00
2010-12-22 02:09:59 +03:00
def _samdb_fetch_schi ( samdb ) :
""" Fetch schemaInfo stored in SamDB using LDB connection """
res = samdb . search ( base = samdb . get_schema_basedn ( ) , expression = " " , scope = SCOPE_BASE , attrs = [ " * " ] )
assert len ( res ) == 1
2010-12-18 06:21:09 +03:00
if ' schemaInfo ' in res [ 0 ] :
2010-12-22 02:09:59 +03:00
pfm_schi = ndr_unpack ( drsblobs . schemaInfoBlob ,
str ( res [ 0 ] [ ' schemaInfo ' ] ) )
2010-12-18 06:21:09 +03:00
else :
pfm_schi = drsblobs . schemaInfoBlob ( )
2018-07-30 09:22:11 +03:00
pfm_schi . marker = 0xFF
2010-12-22 02:09:59 +03:00
return pfm_schi
2010-11-04 00:43:21 +03:00
2018-07-30 09:20:39 +03:00
2010-11-04 00:43:21 +03:00
def _drs_fetch_pfm ( server , samdb , creds , lp ) :
""" Fetch prefixMap using DRS interface """
binding_str = " ncacn_ip_tcp: %s [print,seal] " % server
drs = drsuapi . drsuapi ( binding_str , lp , creds )
2010-11-07 05:55:20 +03:00
( drs_handle , supported_extensions ) = drs_DsBind ( drs )
2018-03-09 17:01:17 +03:00
print ( " DRS Handle: %s " % drs_handle )
2010-11-04 00:43:21 +03:00
req8 = drsuapi . DsGetNCChangesRequest8 ( )
dest_dsa = misc . GUID ( " 9c637462-5b8c-4467-aef2-bdb1f57bc4ef " )
replica_flags = 0
req8 . destination_dsa_guid = dest_dsa
req8 . source_dsa_invocation_id = misc . GUID ( samdb . get_invocation_id ( ) )
req8 . naming_context = drsuapi . DsReplicaObjectIdentifier ( )
2020-07-04 05:27:06 +03:00
req8 . naming_context . dn = samdb . get_schema_basedn ( )
2010-11-04 00:43:21 +03:00
req8 . highwatermark = drsuapi . DsReplicaHighWaterMark ( )
req8 . highwatermark . tmp_highest_usn = 0
req8 . highwatermark . reserved_usn = 0
req8 . highwatermark . highest_usn = 0
req8 . uptodateness_vector = None
req8 . replica_flags = replica_flags
req8 . max_object_count = 0
req8 . max_ndr_size = 402116
req8 . extended_op = 0
req8 . fsmo_info = 0
req8 . partial_attribute_set = None
req8 . partial_attribute_set_ex = None
req8 . mapping_ctr . num_mappings = 0
req8 . mapping_ctr . mappings = None
( level , ctr ) = drs . DsGetNCChanges ( drs_handle , 8 , req8 )
pfm = ctr . mapping_ctr
# check for schemaInfo element
pfm_it = pfm . mappings [ - 1 ]
assert pfm_it . id_prefix == 0
assert pfm_it . oid . length == 21
2019-08-23 03:21:17 +03:00
s = " " . join ( chr ( x ) for x in pfm_it . oid . binary_oid )
2010-12-18 06:21:09 +03:00
pfm_schi = ndr_unpack ( drsblobs . schemaInfoBlob , s )
assert pfm_schi . marker == 0xFF
2010-11-04 00:43:21 +03:00
# remove schemaInfo element
pfm . num_mappings - = 1
2010-12-18 06:21:09 +03:00
return ( pfm , pfm_schi )
2010-11-04 00:43:21 +03:00
2018-07-30 09:20:39 +03:00
2010-11-04 00:43:21 +03:00
def _pfm_verify ( drs_pfm , ldb_pfm ) :
errors = [ ]
if drs_pfm . num_mappings != ldb_pfm . num_mappings :
errors . append ( " Different count of prefixes: drs = %d , ldb = %d "
% ( drs_pfm . num_mappings , ldb_pfm . num_mappings ) )
count = min ( drs_pfm . num_mappings , ldb_pfm . num_mappings )
for i in range ( 0 , count ) :
it_err = [ ]
drs_it = drs_pfm . mappings [ i ]
ldb_it = ldb_pfm . mappings [ i ]
if drs_it . id_prefix != ldb_it . id_prefix :
it_err . append ( " id_prefix " )
if drs_it . oid . length != ldb_it . oid . length :
it_err . append ( " oid.length " )
if drs_it . oid . binary_oid != ldb_it . oid . binary_oid :
it_err . append ( " oid.binary_oid " )
if len ( it_err ) :
errors . append ( " [ %2d ] differences in ( %s ) " % ( i , it_err ) )
return errors
2018-07-30 09:20:39 +03:00
2010-12-18 06:21:09 +03:00
def _pfm_schi_verify ( drs_schi , ldb_schi ) :
errors = [ ]
2018-03-09 17:01:17 +03:00
print ( drs_schi . revision )
print ( drs_schi . invocation_id )
2010-12-18 06:21:09 +03:00
if drs_schi . marker != ldb_schi . marker :
errors . append ( " Different marker in schemaInfo: drs = %d , ldb = %d "
% ( drs_schi . marker , ldb_schi . marker ) )
if drs_schi . revision != ldb_schi . revision :
errors . append ( " Different revision in schemaInfo: drs = %d , ldb = %d "
% ( drs_schi . revision , ldb_schi . revision ) )
if drs_schi . invocation_id != ldb_schi . invocation_id :
errors . append ( " Different invocation_id in schemaInfo: drs = %s , ldb = %s "
% ( drs_schi . invocation_id , ldb_schi . invocation_id ) )
return errors
2018-07-30 09:21:29 +03:00
2010-11-04 00:43:21 +03:00
########### main code ###########
if __name__ == " __main__ " :
# command line parsing
2010-11-21 23:38:14 +03:00
parser = OptionParser ( " pfm_verify.py [options] server " )
2010-11-04 00:43:21 +03:00
sambaopts = options . SambaOptions ( parser )
parser . add_option_group ( sambaopts )
credopts = options . CredentialsOptionsDouble ( parser )
parser . add_option_group ( credopts )
( opts , args ) = parser . parse_args ( )
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
if len ( args ) != 1 :
2018-07-30 09:22:34 +03:00
if " DC_SERVER " not in os . environ . keys ( ) :
2018-07-30 09:13:57 +03:00
parser . error ( " You must supply a server " )
2010-11-04 00:43:21 +03:00
args . append ( os . environ [ " DC_SERVER " ] )
if creds . is_anonymous ( ) :
parser . error ( " You must supply credentials " )
server = args [ 0 ]
samdb = SamDB ( url = " ldap:// %s " % server ,
2010-11-23 18:19:29 +03:00
session_info = system_session ( lp ) ,
2010-11-04 00:43:21 +03:00
credentials = creds , lp = lp )
2010-12-18 06:21:09 +03:00
exit_code = 0
( drs_pfm , drs_schi ) = _drs_fetch_pfm ( server , samdb , creds , lp )
( ldb_pfm , ldb_schi ) = _samdb_fetch_pfm ( samdb )
# verify prefixMaps
2010-11-04 00:43:21 +03:00
errors = _pfm_verify ( drs_pfm , ldb_pfm )
if len ( errors ) :
2018-03-09 17:01:17 +03:00
print ( " prefixMap verification errors: " )
print ( " %s " % errors )
2010-12-18 06:21:09 +03:00
exit_code = 1
# verify schemaInfos
errors = _pfm_schi_verify ( drs_schi , ldb_schi )
if len ( errors ) :
2018-03-09 17:01:17 +03:00
print ( " schemaInfo verification errors: " )
print ( " %s " % errors )
2010-12-18 06:21:09 +03:00
exit_code = 2
if exit_code != 0 :
sys . exit ( exit_code )