2 # -*- coding: utf-8 -*-
4 # script to verify cached prefixMap on remote
5 # server against the prefixMap stored in Schema NC
7 # Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from optparse
import OptionParser
27 sys
.path
.insert(0, "bin/python")
30 import samba
.getopt
as options
31 from ldb
import SCOPE_BASE
, SCOPE_SUBTREE
32 from samba
.dcerpc
import drsuapi
, misc
, drsblobs
33 from samba
.drs_utils
import drs_DsBind
34 from samba
.samdb
import SamDB
35 from samba
.auth
import system_session
36 from samba
.ndr
import ndr_pack
, ndr_unpack
39 def _samdb_fetch_pfm(samdb
):
40 """Fetch prefixMap stored in SamDB using LDB connection"""
41 res
= samdb
.search(base
=samdb
.get_schema_basedn(), expression
="", scope
=SCOPE_BASE
, attrs
=["*"])
43 pfm
= ndr_unpack(drsblobs
.prefixMapBlob
,
44 str(res
[0]['prefixMap']))
46 pfm_schi
= _samdb_fetch_schi(samdb
)
48 return (pfm
.ctr
, pfm_schi
)
50 def _samdb_fetch_schi(samdb
):
51 """Fetch schemaInfo stored in SamDB using LDB connection"""
52 res
= samdb
.search(base
=samdb
.get_schema_basedn(), expression
="", scope
=SCOPE_BASE
, attrs
=["*"])
54 if 'schemaInfo' in res
[0]:
55 pfm_schi
= ndr_unpack(drsblobs
.schemaInfoBlob
,
56 str(res
[0]['schemaInfo']))
58 pfm_schi
= drsblobs
.schemaInfoBlob()
59 pfm_schi
.marker
= 0xFF;
62 def _drs_fetch_pfm(server
, samdb
, creds
, lp
):
63 """Fetch prefixMap using DRS interface"""
64 binding_str
= "ncacn_ip_tcp:%s[print,seal]" % server
66 drs
= drsuapi
.drsuapi(binding_str
, lp
, creds
)
67 (drs_handle
, supported_extensions
) = drs_DsBind(drs
)
68 print "DRS Handle: %s" % drs_handle
70 req8
= drsuapi
.DsGetNCChangesRequest8()
72 dest_dsa
= misc
.GUID("9c637462-5b8c-4467-aef2-bdb1f57bc4ef")
75 req8
.destination_dsa_guid
= dest_dsa
76 req8
.source_dsa_invocation_id
= misc
.GUID(samdb
.get_invocation_id())
77 req8
.naming_context
= drsuapi
.DsReplicaObjectIdentifier()
78 req8
.naming_context
.dn
= unicode(samdb
.get_schema_basedn())
79 req8
.highwatermark
= drsuapi
.DsReplicaHighWaterMark()
80 req8
.highwatermark
.tmp_highest_usn
= 0
81 req8
.highwatermark
.reserved_usn
= 0
82 req8
.highwatermark
.highest_usn
= 0
83 req8
.uptodateness_vector
= None
84 req8
.replica_flags
= replica_flags
85 req8
.max_object_count
= 0
86 req8
.max_ndr_size
= 402116
89 req8
.partial_attribute_set
= None
90 req8
.partial_attribute_set_ex
= None
91 req8
.mapping_ctr
.num_mappings
= 0
92 req8
.mapping_ctr
.mappings
= None
94 (level
, ctr
) = drs
.DsGetNCChanges(drs_handle
, 8, req8
)
96 # check for schemaInfo element
97 pfm_it
= pfm
.mappings
[-1]
98 assert pfm_it
.id_prefix
== 0
99 assert pfm_it
.oid
.length
== 21
101 for x
in pfm_it
.oid
.binary_oid
:
103 pfm_schi
= ndr_unpack(drsblobs
.schemaInfoBlob
, s
)
104 assert pfm_schi
.marker
== 0xFF
105 # remove schemaInfo element
106 pfm
.num_mappings
-= 1
107 return (pfm
, pfm_schi
)
109 def _pfm_verify(drs_pfm
, ldb_pfm
):
111 if drs_pfm
.num_mappings
!= ldb_pfm
.num_mappings
:
112 errors
.append("Different count of prefixes: drs = %d, ldb = %d"
113 % (drs_pfm
.num_mappings
, ldb_pfm
.num_mappings
))
114 count
= min(drs_pfm
.num_mappings
, ldb_pfm
.num_mappings
)
115 for i
in range(0, count
):
117 drs_it
= drs_pfm
.mappings
[i
]
118 ldb_it
= ldb_pfm
.mappings
[i
]
119 if drs_it
.id_prefix
!= ldb_it
.id_prefix
:
120 it_err
.append("id_prefix")
121 if drs_it
.oid
.length
!= ldb_it
.oid
.length
:
122 it_err
.append("oid.length")
123 if drs_it
.oid
.binary_oid
!= ldb_it
.oid
.binary_oid
:
124 it_err
.append("oid.binary_oid")
126 errors
.append("[%2d] differences in (%s)" % (i
, it_err
))
129 def _pfm_schi_verify(drs_schi
, ldb_schi
):
131 print drs_schi
.revision
132 print drs_schi
.invocation_id
133 if drs_schi
.marker
!= ldb_schi
.marker
:
134 errors
.append("Different marker in schemaInfo: drs = %d, ldb = %d"
135 % (drs_schi
.marker
, ldb_schi
.marker
))
136 if drs_schi
.revision
!= ldb_schi
.revision
:
137 errors
.append("Different revision in schemaInfo: drs = %d, ldb = %d"
138 % (drs_schi
.revision
, ldb_schi
.revision
))
139 if drs_schi
.invocation_id
!= ldb_schi
.invocation_id
:
140 errors
.append("Different invocation_id in schemaInfo: drs = %s, ldb = %s"
141 % (drs_schi
.invocation_id
, ldb_schi
.invocation_id
))
144 ########### main code ###########
145 if __name__
== "__main__":
146 # command line parsing
147 parser
= OptionParser("pfm_verify.py [options] server")
148 sambaopts
= options
.SambaOptions(parser
)
149 parser
.add_option_group(sambaopts
)
150 credopts
= options
.CredentialsOptionsDouble(parser
)
151 parser
.add_option_group(credopts
)
153 (opts
, args
) = parser
.parse_args()
155 lp
= sambaopts
.get_loadparm()
156 creds
= credopts
.get_credentials(lp
)
160 if not "DC_SERVER" in os
.environ
.keys():
161 parser
.error("You must supply a server")
162 args
.append(os
.environ
["DC_SERVER"])
164 if creds
.is_anonymous():
165 parser
.error("You must supply credentials")
170 samdb
= SamDB(url
="ldap://%s" % server
,
171 session_info
=system_session(lp
),
172 credentials
=creds
, lp
=lp
)
175 (drs_pfm
, drs_schi
) = _drs_fetch_pfm(server
, samdb
, creds
, lp
)
176 (ldb_pfm
, ldb_schi
) = _samdb_fetch_pfm(samdb
)
178 errors
= _pfm_verify(drs_pfm
, ldb_pfm
)
180 print "prefixMap verification errors:"
184 errors
= _pfm_schi_verify(drs_schi
, ldb_schi
)
186 print "schemaInfo verification errors:"